I mentioned elsewhere, elsewhen, that I’ve recently been drafted into a low-key gamedev team, working in Unity/C#. They’ve got me working on a serious data-crunching item at the moment, and I have SEVERAL questions.
Here’s one of them, for now:
Right now I have a class that I built to be fairly generic because this project involves dealing with many data items which all have a nearly-identical signature except for the datatype they contain, so I just made one class, which privately has a field each for all the possible datatypes.
What I want is to give this class a public Value property, which will just evaluate to the proper datatype on the fly. Is this possible/acceptable in C#?
public class BaseClass<T> {
public T Value { get; set; }
}
public class SubclassTypeA : BaseClass<TypeA> {}
public class SubclassTypeB : BaseClass<TypeB> {}
If you need the T type to conform to an interface or be a subclass of something, you can do something like:
public class BaseClass<T> where T : IComparable { ... }
I haven’t tried this code out because I don’t have any work stuff installed at home but this is how I recall it should work. Go look up generics documentation if you need more info really.
edit: oh I should mention you can just use BaseClass<TypeA> just as if it was a class by itself to save yourself having to write / generate subclasses for all the value types you need to support, as long as you don’t need to extend it with additional type-specific behavior. SubclassTypeA and SubclassTypeB in my example only serve as nicer type aliases
maybe we can revive this and make it the unity / C# thread? @LWJoestar u ok with that?
learning how to do coroutines. am I understanding properly that they are basically just automatic iterators? the INumerator is the iterator an an INumerable is the iteration variable?
The idea here is to start the “Crash” sequence and reload the level after a short delay, the tutorial I was looking at had me doing Invoke(), but I think string references are wack so i figured I’d just learn coroutines
yeah i think ur spot on here. invoke has always been unwieldy in my experience. delegates and coroutines are the way to go.
i think your understanding is correct too. as an amateur programmer i’ve always thought about them as a parallel update but i think iterator is more accurate.
coroutines are a unity feature the leverage the “yield” keyword in C#. that keyword essentially turns whatever block it’s in into an “iterator block”. what’s special about yield return, and the reason unity uses it to implement coroutines, is that it remembers all the STATE of the function (e.g. where it is in the function, the variable values etc) when it hits a yield statement. then, when the function is called again, it continues to execute from where it left off. this way, it effectively interrupts the function call when yield is hit so that other tasks can be done on that same thread, and it will resume the function call where it left off when it gets called again.
sort of. there are two types an iterator block can return:
IEnumerator – an interface that represents the actual iterator (e.g. it has methods to go to the next item, a property to retrieve the current item, and a method to reset the iteration).
IEnumerable – an interface that represents something that can be enumerated (e.g. it only has one method called “GetEnumerator()” which returns, you guessed it, an IEnumerator.) many of the data structures in the C# standard library (e.g. List, Dictionary, etc) implement this.
an iterator block is allowed to return either of these, and the compiler does the magic of creating the class which implements either interface for you depending on the type the iterator block returns.
your comment is mostly correct, but more accurately what is happening behind the scenes is that the yield statement is pausing the function there and remembering the state – it then returns a special value to unity’s coroutine code (in the form of that WaitForSeconds class). the coroutine code reads that value, which tells it to wait a certain amount of time. behind the scenes, unity will wait that amount of time, and only then call your function again which will resume where it left off. it’s not really “looping” the coroutine there (i.e. it never enters that code block again in the interim), it’s just waiting to call it until later.
hopefully this makes sense and isn’t too pedantic. lmk if you want any clarifications!
i had a buddy of mine mention not knowing the “correct way to end a coroutine for garbage collection” which is something i’d never even considered relevant in C#. do you know anything about this? i’ve always just let coroutines finish by getting to the end of the block.
unity should release its reference to a coroutine for garbage collection when it ends naturally, yes (either by yield break or the end of the block). if you’re keeping a reference to the coroutine instance (e.g. so that you can manually stop it) then you’d need to null out the variable storing the coroutine after stopping it so that there are no longer any references to it and C# can garbage collect it.
it looks like unity does not have a way to check if a coroutine finished naturally, so if you have a reference to a coroutine that might have finished and you want to know if you should get rid of it, you’ll need to track that manually within the coroutine itself (e.g. set some shared variable right before the last return or break). i wouldn’t expect this to be a common use case – it seems more likely to me that you either have a finite coroutine that ends using logic within the method itself or you have an infinite one that you sometimes want to stop, either within the method or externally with the coroutine instance.