Random cool C# stuff

edited in General
I get a kick out of finding useful little language features, and since a large part of this community is on Unity/C# projects, I'm hoping this isn't totally out of place. Actually, I hope it'll actually be useful to some people :) I'm pretty sure @HermanTulleken and @Chippit will have tons of stuff to add here as well ;)

So this morning I found a cool trick with concrete generic parameters and extension classes. The problem this solves for me (in some cases) is one of not being able to specify something like a "numeric" generic constraint, so this won't work:
public static T Max<T>(T t1, T t2)
{
  return (t2 > t1)?t2:t1;
}


Now if it happens that the method you're implementing is on a generic class with the numeric type as it's type parameter, you can implement extension methods with a concrete typed version of the generic class as a parameter. Here's a (contrived) example:
public class Range<T> where T : IComparable<T> 
{
    public T Min { get; set; }
    public T Max { get; set; }

    public bool ContainsValue(T value)
    {
        return (Min.CompareTo(value) <= 0) && (value.CompareTo(Max) <= 0);
    }
}
public static class RangeTypeExtensions
{
    public static float GetRandomValue(this Range<float> range, Random random)
    {
        return random.Next(range.Min, range.Max);
    }
    public static int GetRandomValue(this Range<int> range, Random random)
    {
        return random.Next(range.Min, range.Max);
    }
}


Now it can be used like this:
var random = new Random();
var range = new Range()
{
	Min = 0.0f,
	Max = 1.0f
};
float valueInRange = range.GetRandomValue(random);

Obviously you still end up implementing the method for each type you'd want to use it for, but at least you don't have to reimplement the rest of the class.
Thanked by 2raxter konman

Comments

  • fucking love little programming tricks, especially in C#

    Learned today the enums can have extension methods which means you can have something like

    public enum InventoryItemType {MachineGun, Pistol, Shield, PowerUp}
    
    public static class InventoryItemExtensions
    {
        public static GameObject GetPrefab(this InventoryItemType inventoryItemType)
        {
            switch duration 
            {
                case MachineGun: return GameData.instance.machineGunPrefab;
                case Pistol:  return GameData.instance.pistol;
                case Shield: return GameData.instance.shieldPrefab;
                default:   return null;
            }
        }
        public static bool IsWeapon(this InventoryItemType inventoryItemType)
        {
            return inventoryItemType == InventoryItemType.MachineGun ||
                    inventoryItemType == InventoryItemType.Pistol;
        }
    }
    
    public class SomeBehaviour: MonoBehaviour
    {
        void Start()
        {
            Instantiate(InventoryItemType.MachineGun.GetPrefab()); 
             // ^ fuck to the hell to the yeah
        }
    }
    
    // disclaimer, I've not actually compiled this code so it might contain bug/errors but you get the idea I hope


    I am struggling to contain my excitement at this discovery ... srsly guise

    image
  • There's also the ?? operator

    A ?? B
    is shorthand for
    A != null ? A : B


    public class AClass
    {
        SomeClass defaultClass= new SomeClass(/*default parameters*/)
        SomeClass usedClass = null;
        public void SetSomeClass(SomeClass newSomeClass)
        {
            usedClass = newSomeClass ?? defaultClass;
            // ^ this hot shit line of code will set it to newSomeClass unless it is null, in which case it uses defaultClass
    
            // alternatively say you might have a default class you are loading from a file and then a default after that if that even fails
    
            usedClass = newSomeClass ?? LoadSomeClassFromFile() ?? default;
            // ^ if you weren't fucking happy enough, this'll first use newSomeClass if it is not null, then try load something from file, if that is null then it'll use the defaultClass - you can chain it for as long as you want, BAM!
        }
    }


    *ahem cough cough* ... yeah it's pretty fun...
    Thanked by 2Fengol Tenebris_Lab
  • edited
    I should take this moment to point out that the null coalescing operator is dangerous in Unity. If you're using Unity, AVOID it, because it won't work as you expect on MonoBehaviours or any Unity component objects (anything that derives from UnityEngine.Object, actually).

    The reason it breaks is that, despite what Unity wants you to believe, due to how the internal Unity engine operates (and probably because of how its .NET script interface works) references to MonoBehaviour objects are rarely ever actually null. All MonoBehaviours, however, override ToString, Equals and have an explicit bool conversion (eeeuuugh) that makes them appear as if they are under certain circumstances.

    If you destroy a game object or script, the script references will appear to be null. Which is to say

    (bool)destroyedObject // true
    destroyedObject == null // true


    The above is also true if a game object or script is not assigned in the editor.

    However, those objects are not actually null references
    ReferenceEquals(destroyedObject, null) // false
    (System.Object)destroyedObject == null // false
    
    var scriptToDoStuffTo = destroyedObject ?? backupObject; // will be assigned destroyedObject

    So that won't work, because the null coalescing operator sidesteps the Equals override by using (I believe) the generic comparator that other things like Dictionaries also use.

    Basically, the tl;dr here is that ?? won't work for Unity objects. Don't use it unless you want to fight with really, really arb issues down the line.
  • enums can have extension methods
    Yeah, love that little trick so much. Great for having conversion methods in a place that makes total sense (with the enum itself).

    Another interesting one with extensions is that interfaces can have them. So if there's functionality you want all implementations of an interface to have (without explicitly implementing it) that is based on simpler methods they implement as part of the interface, you can add it as an extension to the interface:
    public interface IComparable 
    {
    	int CompareTo(object other);
    }
    
    public static class ComparableExtension 
    {
    	public static bool GreaterThan(this IComparable leftHand, object other) {
    		return leftHand.CompareTo(other) > 0;
    	}
    
    	public static bool LessThan(this IComparable leftHand, object other) {
    		return leftHand.CompareTo(other) < 0;
    	}
    }

    (example from http://www.zorched.net/2008/01/03/implementing-mixins-with-c-extension-methods)
    Thanked by 1raxter
  • edited
    Maybe I'm just OLD Skool here (with emphasis on old), but these new generation C# tricks (as useful and cryptic as they seem) might be fancy and cool when you're an advanced programmer and you're going it solo. Just be mindful jedi's when you use it in a team context where the juniors won't be able to pick up your work, meaning that, the remote holiday you wanted to take to Tristan da Cunha with the missus just might get veto'd by your boss... :) Otherwise very cool stuff.
    Thanked by 1Thelangfordian
  • I think the point of the really good tricks is that they make your code cleaner (and therefore faster to write) and easier to read (and therefore easier to understand). If your junior can't pick up on your work because he's not used to the syntax, then imo you've got a much bigger liability on your hands than just a new generation of C#. :P
  • juniors won't be able to pick up your work
    I think @Elyaradine puts it well, the point of these is to make your code easier to read not harder. With that in mind, if juniors can't learn these useful new tricks from you, their senior developer, then they'll never really progress, will they?

    [rant]
    There's value in being cautious about new features, but these features usually exist for a good reason (especially in a design-by-committee language like C#). If you don't at least consider how they might be useful, you might be missing out on something that could genuinely improve the quality, readability and even performance of your code. Over my years in dev, too often I've seen "old skool" seniors avoid new ways of doing things simply because they're not "old skool". IMO, as a lead/senior dev it's your responsibility to constantly evaluate how you're doing things and improve both your and your team's approach. Lack of this approach, and paranoia about performance without actually testing is why from a code practice point of view game dev is often far behind the curve. Game developers had to be dragged from C to C++, long after the performance concerns were dealt with, then again to using templates, and then again to using managed languages. Some still use C# as if it was C++ with a garbage collector (which leads to it's own issues, because it really isn't as simple as all that).
    [/rant]
    Thanked by 2Elyaradine raxter
  • @mattbenic. I agree...it's your job to figure out the difficult things and then explain them to me :P

    @Elyaradine, I read something recently that said that code gets read far more often than it gets written. So it's worth it to take the time to write something that is easier to read(which means I'm agreeing with you :P). I am beginning to dislike "clever" code more and more. I'd rather have something that reads as close to pseudo code/English as possible. I'm working hard to get myself there(not nearly there yet unfortunately).

    Please keep posting stuff here everyone. I at least appreciate this a lot even tough(or especially since) I don't have anything to add(yet).
  • @Rigormortis

    "I don't have anything to add(yet)"

    You are such a liar!

    ----

    What you say about reading vs. writing is very true. It's the same as writing really readable English: it's damn hard. And language features help, but not as much as you'd imagine. Because writing good code requires thinking, not writing. It also requires something else: caring. (I have read some writer said to be a good writer, you have to be a good person, because only if you care about other people, are you able to spend the time necessary to write clearly. I think it applies doubly so to programmers.).

    ----

    I am totally dependent on extension methods; they are really cool.

    I have a variety of extensions on Unity structs (Transform.SetXY, Transform.AddZ, Color.Lighter, Vector.PerpDot, Vector.Reflect(...), and a tonne on IEnumerator (SampleRandom, SampleGrid, SampleJitteredGrid, Closest, Farthest, InRange, OfType, WhereNotNull, Last, ButFirst, ButLast, ToListString, Combination, Permutation etc.), some on random (mostly for generating point types and tuples) and some for debugging such as these:

    T Log(this T obj) { Debug.Log(obj); return obj;} 
    T Default(this T obj) where T: new {return obj == null ? T() : obj;}


    The mixin pattern is particularly useful for structs, since structs cannot share common implementation.

    Extension methods also help keep hierarchies flat, and together with the mixin pattern, allows you to keep behaviours in small modules. In very generic code this reduces the number of type parameters you need to specify for methods (see also below).

    In Grids we also use the following pattern frequently:

    class X<T> where T : X { }
    class Y : X<Y> { }


    so that methods can be declared with specific types, rather than base types. (For example, you can define Add in the base class, but have the subtype returned when called on a subtype, not the base type) This reduces casting a lot in certain cases, and provides a layer of type safety without giving up shared implementation. (The pattern is also the typical way C# Singletons are implemented as a single base class; all that a class has to do to be a singleton is extend from this class.). (Some people consider this pattern an antipattern, since you don't quite get what you expect. You could conceivably make a class class Z : X<Y> {}, for which it is unclear how the classes relate. I think, however it's utility outweighs this danger).

    (If you use this heavily, you may end up with extremely complicated type definitions, and it's the same type of feeling you get trying to write a const correct program in C++. In this case, its well worth it to define methods as extension methods to reduce the number of types you have to specify).

    @mattbeinc

    "C to C++, long after the performance concerns were dealt with, then again to using templates, and then again to using managed languages." And then from for to foreach ;--) (jk). But I agree with what you are saying. And in the case where there is performance at stake it's one thing, but we also lag behind in software design concepts. Singletons just became popular in game dev when they started to fall out of fashion in the corporate world... Not to mention tools... ;_;

  • edited
    hermantulleken said:
    The mixin pattern is particularly useful for structs, since structs cannot share common implementation.
    Which is a massive deal given how many of Unity's major types are structs, or sealed classes where this also helps.
    but we also lag behind in software design concepts
    Sooo true. Counter-intuitively, game programmers sometimes seem to be averse to innovation and change. Artists on the other hand are always trying and coming up with cool new stuff :)

    Enough philosophical griping, here's another morsel: indexed properties using an inner class. This is one of those that has the potential to be misused and hamper rather than help readability, but in the right contexts it can be useful.
    The problem it solves is the lack of indexable properties in c#. The following isn't valid:
    public property Thing ThingAt[int index]
    {
    	get
    	{
    		return GetThingAt(index);
    	}
    }


    In simple cases, you might have a collection you're returning directly, but (a) that could have access issues (b) sometimes it's not just a simple collection. Also, usually just using a get method (like the one called above) is fine. In some cases though, in would be really nice to just use an indexer shorthand. A real world example in our case is string localization. We have different language localizers per client and If we had to repeatedly use something like Language.Instance.GetLocalizedString(), it really would impact our code readability a lot.

    One way around this is to use an inner class's indexed this operator:
    public class Language : Singleton<Language>
    {
    	// All this inner class does is wrap the GetLocalizedString method
    	public class StringIndexer
    	{
    		readonly Language language;
    		internal StringIndexer(Language language)
    		{
    			this.language = language;
    		}
    
    		public string this[string key]
    		{
    			get
    			{
    				return language.GetLocalizedString(key);
    			}
    		}
    	}
    
    	// This looks like an indexed property to users
    	public static readonly StringIndexer Strings
    
    	public Language()
    	{
    		Strings = new StringIndexer(this);
    		//Other init stuff
    	}
    
    	protected virtual string GetLocalizedString(string key)
    	{
    		// Do stuff to localize string
    	}
    }


    This may seem like a lot of code to do something really simple, and as I warned above has the potential to be less readable. But at the end of the day the benefit is cleaning up the code that uses it, by being able to do this:
    ShowMessage(Language.Strings[title], Language.Strings[message]);


    In our case we have an UpperStrings as well that uses the same approach and wraps some client specific uppercasing behavior, but is just as clean to use.
  • Can I heart this whole thread? So where do you guys go to learn game dev patterns? Coming from the flash (semi corporate) world there seems to be hardly any literature on structuring in the large and surviving large code bases. In fact @hermantulleken s posts on game dev mag seems to be one of the best resources I've found...

    Also mini rant on the fact that c# has so much deliciousness that is just a bad idea on mobile. Lambda syntax and reflection being at the top of the list. Makes me sad.
  • I don't consider myself a c# expert yet. Still finding my feet with the language and the process is been hampered (if only due to my own caution) by moving between the Mono CLR and the .net CLR.

    @mattbenic thanks for that tip on specifying a base type for a generic. I was looking for that a while back when porting some Java io code to Unity. Could not find it back then haven't looked since. I can not tell you how many of the structures I typically have been pointless without this.
    Also mini rant on the fact that c# has so much deliciousness that is just a bad idea on mobile. Lambda syntax and reflection being at the top of the list. Makes me sad.
    There is nothing wrong with using reflection on mobile if you stick to the one thing reflection is best at, factories. Been able to build scripts based on data without having to have a massive long switch statement is absolutely awesome. Of course you could build a long enum with the build methods in it, but that doesn't always work for all cases. The Lambda syntax I would cation against for now mostly due to memory constraints more then performance. Performance can be managed by doing the work at a suitable time, memory can not.

    On the readability of code issue I have never rushed to nor specifically delayed adopting new syntax. When that syntax is more then just sugar I do tend to be cautious and want to know what it does under the hood before adopting it outright. I find that the OO structures and the manner in which they interact is something far more difficult for new developers to pick up then simple syntax stuff. (I will admit I have become a bit lazy about building my OO interaction diagrams. I still prefer Booch notation. http://en.wikipedia.org/wiki/Booch_method although UML sequence diagrams for closer design of interactions is awesome. I think puffy clouds just feel more like gamedev then hard square edges I also feel Booch communicates more visually while UML more in words.) I think its high time I start investigating the c# code documentations tools similar to JavaDoc I am used to been able to pull a very comprehensive code guide with diagrams from my code rather then having to maintain them separately.
    @mattbeinc
    "C to C++, long after the performance concerns were dealt with, then again to using templates, and then again to using managed languages."
    When I was at Psygnosis's Liverpool offices years ago chatting with there Lead Dev he has actually chosen to ban the developers from using templates due to multiple nested templets adding to the total code size quickly as well as often creating situations where the developers could not adjust one behavior without pulling the whole thing down. His issue at the time was less to do with the technology and more to do with the haphazard manner in which it was been applied. I for one am a far bigger fan of generics then templets.
    @mattbeinc
    Singletons just became popular in game dev when they started to fall out of fashion in the corporate world... Not to mention tools... ;_;
    I had singletons in both Toxic Bunny and The Tainted (Although I don't suspect we had called them singletons yet early 1990's was really the beginning of the OO adoption in mainstream). Will admit I am still using them now and more then I would like its just so damn convenient sometimes. In Unity I am moving from singletons to instances on named GameObjects that persist. It gives me a nice way to create alternative start scenes where I can adjust the settings of each object and also a convenient way to have multiple instances. In my limited experience gamedev are the early adopters not the late ones. Perhaps that's changed if so its disappointing. I saw many gamedevs pushing to include managed languages into there games Java been one of them LAU was created for just that (20 years ago) and to make some of the messy code more manageable.

    If I may ask a few questions I have since I am coming from a Java background there are still some things I am used to having that I haven't found suitable replacements for in c# yet.

    In Java a nested inner class not specifically declared as static is automatically considered to be part of the parent and all instances gain intimidate access to the parent class.

    class A {
        private int t;
    
        public B CreateB(){
            return new B();
        }
    
        class B {
            public int NewIdAndIncrement(){
                return t++;
            }
        }
    
    }


    The example is bogus, but the point is its often useful to be able to expose some methods in the factory parent that all the classes it builds can access without having to expose those methods to everyone. Is there a convenient way to do this in c# in java its the inner class in c++ I would just declare the base class of the children as a friend. In c#?
  • edited
    Interesting and subjective. (Where's the up-vote whole thread button?)

    I'm a big fan of creating neat, readable, loosely coupled and maintainable code (specifically SOLID principles and Gang of Four Design patterns).

    In our world maintainability means the whole team (consisting of various skill leveled programmers) need to work together.
    Where our client's client is SARS, where deadlines aren't negotiable estimations, but fixed targets.

    Also we've had a scenario where a lead developer over-engineered a module (job security?) using all the new generation C# features and fancy tricks. We had to re-factor his work so that it was simpler to understand and easier to maintain.

    So it is within that context that I raise my concerns re: new language features and getting fancy. Yes some are useful and I get an endorphin buzz when it builds :-P

    Also, IMHO some of these new powerful features do NOT make the code more readable - just look at LINQ lambda expressions for example.

    Conciseness, yes - Readability? Erm, no. So horses for courses. ;)

    PS: I'm not shooting down this thread, just adding a different perspective.
  • edited
    konman said:
    PS: I'm not shooting down this thread, just adding a different perspective. Please add more useful code snippets,tips or code smells!
    Yeah of course, multiple perspectives FTW!! :)
    konman said:
    just look at LINQ lambda expressions for example
    See now there's an example of something that on the one hand can lead to hard to understand code, but can also massively improve it, depending on use. I do think it's easier for corporate devs that regularly work with relational DBs to pick up though, because they often need to think in that sort of language (SQL).
    I avoid linq in any realtime code, simply because of the additional garbage generation, but I'm happy to use it in loading and tool scenarios. Besides being less garbage sensitive, this also tends to be code that would need reworking anyway in case of a technology change. I know @hermantulleken is a total linq fanboi ;)
    Here's an example where personally I think the code is far more concise and readable than the non-linq alternative, but I also know some devs that haven't used linq might disagree. To me this is more like the pure logic of what I want to achieve, than a bunch of nested fors:
    string[] paths = EditorUtility.CollectDependencies(Selection.objects)
                .Select((uo) => AssetDatabase.GetAssetPath(uo))
                .Distinct()
                .ToArray();
    So where do you guys go to learn game dev patterns?
    Usually stackoverflow.com provides the answer, or leads me to the eventual answer. Some of the actual C#/.Net development team contribute to the site, and their answers tend to get into the details about implementation. In other cases, people will answer referencing MS documentation or articles that lead to more insight. And then of course there's the wonder of ILSpy to do some extra poking if I'm worried about how something is implemented :)
    tbulford said:
    its often useful to be able to expose some methods in the factory parent that all the classes it builds can access without having to expose those methods to everyone. Is there a convenient way to do this in c#
    There is sadly no direct equivalent to friend. If it wasn't such a complete PITA to use multiple assemblies in Unity projects you could use internal, but you can't so bleh! You have two options I'm aware of as workarounds:
    1. If the case allows for it, declare the field or method you want exposed to the inner class private static:
    class A 
    {
        private static int t;
    
        public B CreateB()
        {
            return new B();
        }
    
        class B 
    	{
            public int NewIdAndIncrement()
            {
                return t++;
            }
        }
    }

    The difference here looks like java inner class instances implicitly have a reference to their outer class instance they are related to (don't remember that..), while inner class instances in C# are in no way related to a particular instance of the outer class.
    2. Give the inner class a reference to the outer class:
    class A 
    {
        private static int t;
    
        public B CreateB()
        {
            return new B();
        }
    
        class B 
    	{
    		private A a;
    		internal B(A a)
    		{
    			this.a = a;
    		} 
            public int NewIdAndIncrement()
            {
                return a.t++;
            }
        }
    }

    If you're concerned about circular references here, use a WeakReference. If you want this access passed on to children of the inner class, you'll basically need to wrap access to the private stuff in the outer class in protected methods on the inner class.

  • I'm gonna make it this year's goal to understand everything in this thread >_<
  • edited
    So where do you guys go to learn game dev patterns?
    What @mattbenic said. Specifically, for C#, you can read everything this guy writes http://stackoverflow.com/users/88656/eric-lippert (on StakOverflow and his blogs). He's was one of the language designers; he writes long thoughtful answers and posts and knows the innards of the language really well.

    Also, you get to absorb some stuff working with other programmers (although because all the gamedev companies are so small, the opportunity is rare). And for game dev specific stuff, you will have to just invent some patterns and idioms on your own. The way we need to solve difficult problems across several frames, and our more complicated logic visualisation (thinking here of things like transitions, and use of randomness to spice things up), for example, are a bit different from problems in other fields.
    If you're concerned about circular references here
    You need not worry about it for the sake of GC though.

    http://stackoverflow.com/questions/9604197/circular-reference-in-same-assembly-a-bad-thing
  • edited
    hermantulleken said:
    You need not worry about it for the sake of GC though.
    Thanks, I thought I remembered seeing something along those lines but couldn't find it again :) If that's true then yeah you never really need to bother with WeakReference.

    However phrases like:
    Eric Lippert said:
    still worry me a little because I don't know how true that is in Mono or compact framework in general. I know in The Harvest we had a tons of circular references in our scene graph (this was just one of those C++ to a garbage collected language things that happened a lot) and it did actually cause leaks between scenes on the then-WP7 compact framework. This may have been the complexity of the graph confusing the GC though, and not a failing in the GC itself. Definitely something I need to test sometime in Mono/Unity.
  • @mattbenic yip handing a reference to the parent class is what I ended up doing. Its a bit of a pain but not the end of the world. In Java the inner child class automatically has that reference to the parent class it was create in.
    If it wasn't such a complete PITA to use multiple assemblies in Unity projects you could use internal, but you can't so bleh! You have two options I'm aware of as workarounds:
    Pain in the ass? Ok I am not finding that perhaps not using different assemblies enough to, but since I am currently embarking on a made rush to split parts of my applications into different assemblies/namespaces I should ask why its a pain in the ass? I am not 100% clear on the distinction of namespace and assembly in c# that might be a problem worth fixing ASAP :)
  • tbulford said:
    I am not 100% clear on the distinction of namespace and assembly in c# that might be a problem worth fixing ASAP
    Namespaces and assemblies are not at all the same thing.
    Namespaces in C# are like packages in Java, they just serve to separate classes into logical collections. In Java, if no access modifier (private, protected, public) is specifed, the default is package-private access (reference), there is no equivalent access modifier in C#.
    Assemblies on the other hand are essentially compiled binary files containing collections of usable classes, for our purposes they are dlls or exes containing our compiled code. C#'s internal modifier limits access to other classes in the same assembly.

    The reason I say using different assemblies is a pain in the ass is Unity has it's own way of breaking up your code into assemblies based on their compilation order-the dll projects in your monodev or VS solutions represent these assemblies. As far as I'm aware, the only way to introduce other assemblies into the mix is as precompiled dlls, or by setting up your own custom solution and working on individual projects there. I may be wrong, and there may be an easy way to introduce additional assembly projects to the autogenerated (by Unity) solutions without having to re-add them every time Unity changes them.
  • edited
    Ah yes I have seen this. I have one custom assembly I use build it in Visual Studio add several dll's into the various folders for each runtime. It's painful to build outside Unity then include the file. Especially if it's something you want to tweak often.
  • raxter said:
    There's also the ?? operator

    A ?? B
    is shorthand for
    A != null ? A : B
    WTF! Shweet
  • raxter said:
    There's also the ?? operator

    A ?? B
    is shorthand for
    A != null ? A : B
    WTF! Shweet
    Don't miss the post after that: ;)
    Chippit said:
    I should take this moment to point out that the null coalescing operator is dangerous in Unity. If you're using Unity, AVOID it, because it won't work as you expect on MonoBehaviours or any Unity component objects (anything that derives from UnityEngine.Object, actually).
  • @dreampunchboy i know right, super cool!

    But read @Chippit's response post, it will NOT work with any Unity Component/MonoBehaviour or GameObject (I think anything derived from UnityEngine.Object)

    literally yesterday I was like harharhar I'm going to use the ?? operator and it'll work just fine harharhar ...

    public class ResizeToAnchor
    {
        [SerializeField]
        Transform target = null;
    
        // <other fields and such>
    
        void Update()
        {
            Transform t = target ?? transform;
            // HARHARHAR @Chippit I'll show you!
    
            // <insert some other code using 't'>
            // 't' is actually set to target even though target is null because of reasons in @Chippit's post above
    
            // damn yooooooooooooooooou! ;p
        }
    
    }


    so be careful with it, mkay :)
    Thanked by 1Chippit
  • @raxter Oh ok, didn't read he's comment. :(
  • edited
    Hmmm this is such an old issue that I wondered if they fixed it, so I also did a test, and in Unity 4.3~ it seems to work as expected... If they are still trying to simulate null (and what a dumb dumb dumb thing to do MG), I wonder how it is working, since you cannot overload ??. I thought it may be possible with some implicit casting, but that just sounds super dangerous...

    @raxter what version of Unity did you use?
  • 4.3 ... I think (on my other computer but 90% sure that is 4.3)
    it seems to work as expected
    as expected in that it worked or did not work?
  • edited

    it seems to work as expected
    He he, should have said work as it should.
    And now I did a another test and it seems not all components are equal: if fails with Transform, but not my own MonoBehaviour... The inconsistency makes it pretty useless.

    (Edit: More interesting than useful, it seems to work for MonoBehaviour itself, but not Component or Behaviour)
  • (Edit: More interesting than useful, it seems to work for MonoBehaviour itself, but not Component or Behaviour)
    What was your test case here?
  • edited
    @Chippit

    public class Test : MonoBehaviour
    {
       public TypeToTest variable = null;
    
       public void Start()
       {
           TypeToTest someOtherVariable = variable ?? someNonNullThingThatCanBeAssignedTo_someOtherVariable;
    
           someOtherVariable.transform.position = new Vector3(100, 100, 100); 
           //gives error if someOtherVariable is still null (or "null" ?)
    
           //or if using Transform, just someOtherVariable.position = ...
       }
    }


    Hmmm did I do something stupid?
  • Is Test a MonoBehaviour? Something that the inspector serializes? The problem isn't specifically that the types can't be null, it's that Unity makes them such when deserializing or destroying them. You can always assign a reference of something to null in C#, so if your test class isn't a MonoBehaviour, what you're doing WILL work as intended, yeah!
  • OK the test class was a MonoBehaviour. My main "point" was the inconsistencies for working between TypeToTest being a Monobehaviour or derrived class, vs. Component, Behaviour, Transform (at least in this case). By the sound of it, it may fail in even more cases. ("point" to be understood as a passing curiosity :P)
  • For those of you who are extremely interested in C#, the compiler was made open source today.

    http://roslyn.codeplex.com/
  • Squidcor said:
    For those of you who are extremely interested in C#, the compiler was made open source today.

    http://roslyn.codeplex.com/
    Ooooh, this is going to be a great bonus for the third part tools community (no, I'm not one of them :P)
  • So this may be more of a grr thing (because it's to get around a Unity limitation) than a cool thing, but at least it's useful.
    If you have a generic class like this:
    [Serializable]
    public class Range<T>
    {
    	public T Min;
    	public T Max;
    
    	// Add lots of really useful generic functionality here..
    }


    And then you use it in a MonoBehavior or ten:
    public Foo : MonoBehavior
    {
    	public Range<float> FBar;
    	public Range<int> IBar;
    	public Range<decimal> DBar;
    }


    Unity, quite stupidly, doesn't display the generic fields in the inspector even though the concrete types of Min and Max would be known at compile time.

    Thankfully, there's a workaround. You can create concrete subclasses of the generic, also with the Serializable attribute, and Unity will correctly display them:
    [Serializable]
    public class RangeF : Range<float> { }
    [Serializable]
    public class RangeI : Range<int> { }
    [Serializable]
    public class RangeD : Range<double> { }


    Don't forget to update your monobehavior..
    public Foo : MonoBehavior
    {
    	public RangeF FBar;
    	public RangeI IBar;
    	public RangeD DBar;
    }


    Now this may seem to defeat the point of generics somewhat, but at least you're not re-implementing all your useful functionality, and when you need a new concrete type, you just need to add a new subclass.

    Also, if you're using var in local scope, the only place you should ever need to use these subclasses is in the fields actually exposed in the inspector. If you're really pedantic, you could even keep those private (and use UnityEngine.SerializeField), and rather expose them to code with a property that uses the base template type:
    public Foo : MonoBehavior
    {
    	[SerializeField]
    	private RangeF fBar;
    
    	public Range<float> FBar { get; set; }
    
    	void Awake()
    	{
    		FBar = fBar;
    	}
    }



  • Here's another one that's a workaround for a C# issue. So it turns out when you use an enum as the key to a Dictionary as in the following super-contrived example:
    public enum FooBar
    {
    	Foo, 
    	Bar
    }
    
    public class Thingy
    {
    	private Dictionary<FooBar, object> fooBarDict = new Dictionary<FooBar, object>(); 
    
    	// Omitting initialization and stuff
    
    	public object GiveItToMeBaby(FooBar key)
    	{
    		if (fooBarDict.ContainsKey(key))
    		{
    			return fooBarDict[key];
    		}
    		return string.Empty;
    	}
    }


    Both the ContainsKey and index operators -and pretty much anything else you'd expect to do with a dict- will cause boxing of the key value, and thus generate garbage. This is because by default the dictionary uses EqualityComparer.Default, which in turn uses Object.Equals and Object.GetHashCode to get hash keys and determine equality.

    Unfortunately there doesn't seem to be an elegant generic solution that doesn't also box or otherwise allocate (there's one in the comments of this article that generates the necessary IL opcodes directly, but without testing it on Unity in general and iOS in particular I wouldn't jump at suggesting it). So what you need to do is create an IEqualityComparer implementation for each enum you want to use as a dictionary key (often enough to care about the allocations), and pass it to the dictionary:
    public enum FooBar
    {
    	Foo, 
    	Bar
    }
    public class FooBarEqualityComparer : IEqualityComparer<FooBar>
    {
        public static readonly FooBarEqualityComparer Comparer = new FooBarEqualityComparer();
    
        public bool Equals(FooBar x, FooBar y)
        {
            return x == y;
        }
    
        public int GetHashCode(FooBar obj)
        {
            return (int)obj;
        }
    }
    
    
    public class Thingy
    {
    	private Dictionary<FooBar, object> fooBarDict = new Dictionary<FooBar, object>(FooBarEqualityComparer.Comparer); 
    
    	// Omitting initialization and stuff
    
    	public object GiveItToMeBaby(FooBar key)
    	{
    		if (fooBarDict.ContainsKey(key))
    		{
    			return fooBarDict[key];
    		}
    		return string.Empty;
    	}
    }

  • @mattbenic: I may be completely wrong with this (because I'm not up to speed on all the lower level stuff), but instead of using the enum itself as key, wouldn't parsing the enum to an int and using the int as key be slightly more efficient?
  • It could well be (I'd have to test if that doesn't also box), but I'm not a fan of casting back and forth between an enum and it's underlying type unless absolutely necessary. To me that removes the safety benefits of using an enum in the first place.
    I'm not speaking about hypothetical risks here either :) I've had to deal with cases in my current project where assumptions around converting to int and then back to a different enum have led to nasty, hard to find issues.
  • This shocked me so profusely that I had to take a look for myself in the disassembly of mscorlib.dll. I've discovered that at some point between .NET 2.0 and .NET 4.0, MS improved the situation by introducing an internal System.Collections.Generic.EnumEqualityComparer<T> that is selected by EqualityComparer<T>.Default when T is an enum and its underlying type is int. I can't say whether the current version of Mono (or the ancient version used by Unity) causes boxing with enum dictionary keys.
  • edited
    The fix @mattbenic describes is also necessary to get dictionaries to work with the AOT compiler when you use value types as keys. :(

    http://gamelogic.co.za/2014/01/11/workarounds-for-aot-compiler-limitations/
  • edited
    I performed a non-development Win32 build of a Unity scene and opened up the bundled mscorlib.dll in ILSpy. EqualityComparer<T>.Default gives no special treatment to types that don't implement IEquatable<T> (which includes enums).

    Another possible solution though is an old C hack that uses the enum as an index into an array. It's much faster than dictionary lookups but is only feasible if you anticipate most of the keys will have values, and the members of the enum have sequential integral values that start at 0 (it also involves casting which will put some folks off).
    public enum FooBar
    {
    	Foo, 
    	Bar
    }
    
    public class Thingy
    {
    	private object[] fooBarArr = new object[Enum.GetValues(typeof(FooBar)).Length];
    
    	// Omitting initialization and stuff
    
    	public object GiveItToMeBaby(FooBar key)
    	{
    		object result = fooBarArr[(int)key];
    		return result; // unused key results in null value;
    	}
    }
  • edited
    @ChristopherM yeah, I neglected to mention it's been fixed in .Net 4 (not 3.5). Of course there's no telling when Mono will be up to date with 4, never mind Unity's version of Mono.

    The array option is of course a perfectly valid alternative, the only reason we really use a dict is convenience. You could probably write a dict like wrapper around an array specifically for enums that would have the same convenience and none of the performance concerns, and wouldn't need the above workaround.
Sign In or Register to comment.