Xbox LIVE Indie Games
Sort Discussions: Previous Discussion Next Discussion
Page 1 of 2 (32 posts) 1 2 Next >

Clean ways to dynamically add inherited items to a list?

Last post 10/16/2009 7:16 PM by Third Party Ninjas. 31 replies.
  • 9/30/2009 9:40 AM

    Clean ways to dynamically add inherited items to a list?

    Hi,

    I've got a bit of a basic problem and I'm pretty sure that more clever minds than me must have long since solved it. I don't have any actual code but have written out the case as it could occur so forgive me if the names are a bit odd.

    I've got a List<> that takes Instance_Enemy class items. I also have classes that inherit from Instance_Enemy, named Instance_Enemy_Type_001, Instance_Enemy_Type_002, etc.

    So adding an "enemy" would be i.e. done through List_Enemies.Add(new Instance_Enemy_Type_001());.

    How would I dynamically go about adding the different sub types without resorting to things such as a switch? So i.e. List_Enemies.Add(new [VARIABLE_NAME]()); (I know that it doesn't work but I don't know any other way to describe it).
  • 9/30/2009 9:43 AM In reply to

    Re: Clean ways to dynamically add inherited items to a list?

    System.Activator.CreateInstance(...)
  • 9/30/2009 12:14 PM In reply to

    Re: Clean ways to dynamically add inherited items to a list?

    Thanks for the reply. I've read quite a bit on it but I'm a bit stuck.

    As far as I can gather, it should i.e. be used as following:

    1             Instance_Enemy e; 
    2             Type t = Type.GetType("Instance_Enemy_Type_001"true); 
    3             Object[] args = { _position }; 
    4             e = (Instance_Enemy)Activator.CreateInstance(t, args); 

    This however gives me an "TypeLoadException was unhandled" error on the Type t. Any idea's what I'm doing wrong because all the material i can find more or less puts it as above.
  • 9/30/2009 12:33 PM In reply to

    Re: Clean ways to dynamically add inherited items to a list?

    Type t = typeof(Instance_Enemy_Type_001);

    Give that a shot instead.
  • 9/30/2009 12:34 PM In reply to

    Re: Clean ways to dynamically add inherited items to a list?

    Xerx3s:
    Thanks for the reply. I've read quite a bit on it but I'm a bit stuck.

    As far as I can gather, it should i.e. be used as following:

    1             Instance_Enemy e; 
    2             Type t = Type.GetType("Instance_Enemy_Type_001"true); 
    3             Object[] args = { _position }; 
    4             e = (Instance_Enemy)Activator.CreateInstance(t, args); 

    This however gives me an "TypeLoadException was unhandled" error on the Type t. Any idea's what I'm doing wrong because all the material i can find more or less puts it as above.


    Is Instance_Enemy_Type_001 within a namespace? If so pass in "mynamepace.Instance_Enemy_Type_001" to the GetType method. If that fails, try fully qualifying the type name with the Assembly name.
  • 9/30/2009 12:43 PM In reply to

    Re: Clean ways to dynamically add inherited items to a list?

    Craig Martin:
    Xerx3s:
    Thanks for the reply. I've read quite a bit on it but I'm a bit stuck.

    As far as I can gather, it should i.e. be used as following:

    1             Instance_Enemy e; 
    2             Type t = Type.GetType("Instance_Enemy_Type_001"true); 
    3             Object[] args = { _position }; 
    4             e = (Instance_Enemy)Activator.CreateInstance(t, args); 

    This however gives me an "TypeLoadException was unhandled" error on the Type t. Any idea's what I'm doing wrong because all the material i can find more or less puts it as above.


    Is Instance_Enemy_Type_001 within a namespace? If so pass in "mynamepace.Instance_Enemy_Type_001" to the GetType method. If that fails, try fully qualifying the type name with the Assembly name.


    Cheers mate, that did the trick! What a silly thing, I'd expect it to be able to find it if it was within the same namespace! :)
  • 9/30/2009 12:45 PM In reply to

    Re: Clean ways to dynamically add inherited items to a list?

    Cheers for the help all, that was the last bit I needed for my uber skynet AI! ;)
  • 9/30/2009 12:46 PM In reply to

    Re: Clean ways to dynamically add inherited items to a list?

    Xerx3s:
    I also have classes that inherit from Instance_Enemy, named Instance_Enemy_Type_001, Instance_Enemy_Type_002, etc.

    Why? Do you have to have the child classes or could you add members to the base class to do what you want? What's the difference between the base and child classes?
  • 9/30/2009 1:57 PM In reply to

    Re: Clean ways to dynamically add inherited items to a list?

    Keep in mind that the performance for this method is likely much worse than just making a switch statement. You're allocating a string, an array, and performing reflection to create the object. Unless you have some absurd number of classes, I'd say just use an enum and a switch and call it good.
  • 9/30/2009 3:36 PM In reply to

    Re: Clean ways to dynamically add inherited items to a list?

    Nick Gravelyn:
    Keep in mind that the performance for this method is likely much worse than just making a switch statement. You're allocating a string, an array, and performing reflection to create the object. Unless you have some absurd number of classes, I'd say just use an enum and a switch and call it good.

    I agree with this. The factory method pattern comes to mind when solving this issue.
  • 9/30/2009 5:18 PM In reply to

    Re: Clean ways to dynamically add inherited items to a list?

    Nick Gravelyn:
    Keep in mind that the performance for this method is likely much worse than just making a switch statement. You're allocating a string, an array, and performing reflection to create the object. Unless you have some absurd number of classes, I'd say just use an enum and a switch and call it good.


    I'd say the Activator approach is better if you're doing it at load time, since the factory approach is uglier from a maintainability standpoint.  There's nothing I hate more than having to go change code every time I add a new class.
  • 9/30/2009 5:34 PM In reply to

    Re: Clean ways to dynamically add inherited items to a list?

    MJP:
    Nick Gravelyn:
    Keep in mind that the performance for this method is likely much worse than just making a switch statement. You're allocating a string, an array, and performing reflection to create the object. Unless you have some absurd number of classes, I'd say just use an enum and a switch and call it good.


    I'd say the Activator approach is better if you're doing it at load time, since the factory approach is uglier from a maintainability standpoint.  There's nothing I hate more than having to go change code every time I add a new class.
    True, if this is a load time only type of thing, then stick with it since it works. But if you are going to be doing this often throughout the game, you'll probably want a more efficient system.
  • 10/14/2009 3:58 PM In reply to

    Re: Clean ways to dynamically add inherited items to a list?

    Nick Gravelyn:
    Keep in mind that the performance for this method is likely much worse than just making a switch statement. You're allocating a string, an array, and performing reflection to create the object. Unless you have some absurd number of classes, I'd say just use an enum and a switch and call it good.


    Yeah but then I wouldn't learn something new! :)

    Anyway, I pretty much worked out the entire (mini) game and thought I'd port it to the 360 so I could play it with some mates. Que, problem. :)

    It gives me "No overload for method 'CreateInstance' takes '2' arguments". I found some old 2007 forum posts which suggested that the 360 library doesn't support it (but windows does). Any suggestions?

    The code I use now looks something like this (crudely compacted):

    1 (CLASS_NAME)Activator.CreateInstance( 
    2                 Type.GetType("NAMESPACE.CLASS_NAME"true), 
    3                 new Object[] { ARGUMENTS }) 

  • 10/14/2009 4:12 PM In reply to

    Re: Clean ways to dynamically add inherited items to a list?

    Yep, that overload of CreateInstance doesn't exist in the compact framework.  But there's another way.  Here's a bit of code copied directly from my current game:

                ConstructorInfo constructorInfo = actorData.Type.GetConstructor(new Type[] { actorData.GetType() }); 
                return (Actor)constructorInfo.Invoke(new object[] { actorData }); 
     

    GetConstructor takes an array of types to get the correct constructor.  (In this case, my constructor takes an ActorData.)
    Invoke takes an array of objects, just like the overload of CreateInstance you were calling before.

    Let me know if that isn't clear, and I'll be glad to help.
  • 10/14/2009 6:29 PM In reply to

    Re: Clean ways to dynamically add inherited items to a list?

    Chounard:
    Yep, that overload of CreateInstance doesn't exist in the compact framework.  But there's another way.  Here's a bit of code copied directly from my current game:

                ConstructorInfo constructorInfo = actorData.Type.GetConstructor(new Type[] { actorData.GetType() }); 
                return (Actor)constructorInfo.Invoke(new object[] { actorData }); 
     

    GetConstructor takes an array of types to get the correct constructor.  (In this case, my constructor takes an ActorData.)
    Invoke takes an array of objects, just like the overload of CreateInstance you were calling before.

    Let me know if that isn't clear, and I'll be glad to help.


    Hey, cheers for the reply. At the moment I'm at a complete loss to understand that but then I'm absolutely knackered so I'll call it a day and start fresh tomorrow. :)
  • 10/14/2009 10:29 PM In reply to

    Re: Clean ways to dynamically add inherited items to a list?

    I know what I will post will make some people scream in their sleep and they hate that kind of stuff.

    Don't care... It works, and I use it plenty. I don't think it's slower or faster.

        public static class DynArray 
        { 
            // Append an new item at the end of an array, expending it. 
            public static void Append<T>(ref T[] pst_OldArray, T NewItem) 
            { 
                int i_Lenght = GetArraySize<T>(ref pst_OldArray); 
                i_Lenght++; 
     
                T[] NewArray = new T[i_Lenght]; 
     
                if (pst_OldArray != null
                    pst_OldArray.CopyTo(NewArray, 0); 
     
                NewArray[i_Lenght - 1] = NewItem; 
     
                pst_OldArray = NewArray; 
            } 
        } 

    I know, I know. Not using List<> or ArrayList.
    Maybe not so clean on the deep...

    So what I had an object in my World, it goes :

    DynArray.Append<GameObject>(ref WorldObjects, _pst_Object); 

    Doesn't matter what is the subclass of _pst_Object and long as it inherites GameObject.
    I find it kinda clean on the upper level. (personal opinion)
    Made myself a collection of function to handle dynamic arrays like that one.

    I'm maybe seeking too deep...
    Happens often.
    Or maybe I didn't understood the initial problem. :)
    That also happen often. ;)
  • 10/14/2009 10:41 PM In reply to

    Re: Clean ways to dynamically add inherited items to a list?

    LightStriker:
    I know what I will post will make some people scream in their sleep and they hate that kind of stuff.

    Don't care... It works, and I use it plenty. I don't think it's slower or faster.

        public static class DynArray 
        { 
            // Append an new item at the end of an array, expending it. 
            public static void Append<T>(ref T[] pst_OldArray, T NewItem) 
            { 
                int i_Lenght = GetArraySize<T>(ref pst_OldArray); 
                i_Lenght++; 
     
                T[] NewArray = new T[i_Lenght]; 
     
                if (pst_OldArray != null
                    pst_OldArray.CopyTo(NewArray, 0); 
     
                NewArray[i_Lenght - 1] = NewItem; 
     
                pst_OldArray = NewArray; 
            } 
        } 

    I know, I know. Not using List<> or ArrayList.
    Maybe not so clean on the deep...

    So what I had an object in my World, it goes :

    DynArray.Append<GameObject>(ref WorldObjects, _pst_Object); 

    Doesn't matter what is the subclass of _pst_Object and long as it inherites GameObject.
    I find it kinda clean on the upper level. (personal opinion)
    Made myself a collection of function to handle dynamic arrays like that one.

    I'm maybe seeking too deep...
    Happens often.
    Or maybe I didn't understood the initial problem. :)
    That also happen often. ;)


    It creates/copies to a new array every append :s. I wouldn't be able to sleep at night :)
  • 10/14/2009 10:47 PM In reply to

    Re: Clean ways to dynamically add inherited items to a list?

    Craig Martin:

    It creates/copies to a new array every append :s. I wouldn't be able to sleep at night :)


    True... But since it put it in the old pointer (ref), wouldn't the old stuff be garbage collected since it's not targeted by anybody anymore?
    I heard C# garbage collection is quite good.

    Or is creating arrays and copying it super slow?

    Don't be shy to point me the terribly obvious errors I do. It's probably not that obvious to me and I prefer to learn.
  • 10/14/2009 11:07 PM In reply to

    Re: Clean ways to dynamically add inherited items to a list?

    Yes, the adds will become slow when you have large numbers of items.  I suspect the data copying would become the bottleneck.

    Dynamic arrays (such as like List<T>) usually work by allocating more space than they need, and grow by large amounts (e.g. they might double) once that space is filled up.  So the re-allocation happens much less frequently.  You could change your code to do that, but of course since you're just using a raw array that means people would be able to index items that are out of range and get undefined results. List<T>, I assume, overrides the [] operator so that indexing out of range will throw an exception even if the internal representation has enough space allocated.

    On the Xbox (or rather the compact .net framework), the gc is not as advanced, so you may have noticeable pauses which will become more frequent the more garbage collections you need.
  • 10/15/2009 1:37 AM In reply to

    Re: Clean ways to dynamically add inherited items to a list?

    LightStriker:
    True... But since it put it in the old pointer (ref), wouldn't the old stuff be garbage collected since it's not targeted by anybody anymore?


    Arrays are already reference types, so using the ref keyword is pointless. It's worse than pointless, it obfuscates the code.

    LightStriker:
    I heard C# garbage collection is quite good.


    It's pretty good on the PC, not so good on the XBox.

    LightStriker:
    Or is creating arrays and copying it super slow?


    It won't be fast if you have hundreds or thousands of elements in the array.

    Recreating the array each append is creating more garbage than necessary.

    Just use List<T>. It's standard, well implemented and solves all the problems you're trying to solve, and solves them better.
  • 10/15/2009 2:13 AM In reply to

    Re: Clean ways to dynamically add inherited items to a list?

    Craig Martin:
    LightStriker:
    True... But since it put it in the old pointer (ref), wouldn't the old stuff be garbage collected since it's not targeted by anybody anymore?


    Arrays are already reference types, so using the ref keyword is pointless. It's worse than pointless, it obfuscates the code.


    Now, I may not be a good programmer YET, but that sound terrible.
    I know data inside an array are pointer. From what I understand, arrays in C# are tables of pointers.
    But it's the first time I hear arrays are themselves pointers.

    But NOT using the ref keyword (or * in C/C++) would be terrible. As far as I know, not using it in this case just made my code not work.
    I'm probably not understanding what you mean by "Arrays are already reference types, so using the ref keyword is pointless. It's worse than pointless, it obfuscates the code."

    Example :

    public int[] mi_Test = { 0, 1 }; 
     
    private void ArrayRef1(int[] i_Array) 
        int[] i_A = { 4, 5 }; 
     
        i_Array = i_A; 
     
    private void ArrayRef2(ref int[] i_Array) 
        int[] i_A = { 6, 7 }; 
     
        i_Array = i_A; 
     
    public main() 
        ArrayRef1(mi_Test); 
     
        ArrayRef2(ref mi_Test); 
             

    In main(), after first function call, mi_Test is {0, 1}.
    After second function call, mi_Test is {6, 7}.
  • 10/15/2009 3:09 AM In reply to

    Re: Clean ways to dynamically add inherited items to a list?

    The ref keyword is definitely not pointless for reference types like arrays. The way you've designed it, as you suspected, it is actually essential for the code to work, since your function changes the value of the original array (not the values in the array). That isn't implying that this is good design though (and it's not very common I see C# code that uses ref on a reference type).

    Why not just use List<T>?
  • 10/15/2009 3:38 AM In reply to

    Re: Clean ways to dynamically add inherited items to a list?

    No reason aside I dunno it enough yet. Still trying it out.
    Like he said above it's probably the best and probably also does it best.
  • 10/15/2009 6:37 AM In reply to

    Re: Clean ways to dynamically add inherited items to a list?

    Sorry yea I didn't notice the use of static for the DynArray class and Append method. So the ref keyword is needed for that implementation, because without it the array reference is passed to the Append method by value, so you can't change the caller reference.

    Below would also work without the ref keyword:

        public static class DynArray    
        {    
            // Append an new item at the end of an array, expending it.    
            public static T[] Append<T>(T[] pst_OldArray, T NewItem)    
            {    
                int i_Lenght = GetArraySize<T>(ref pst_OldArray); 
                i_Lenght++;    
        
                T[] NewArray = new T[i_Lenght];    
        
                if (pst_OldArray != null)    
                    pst_OldArray.CopyTo(NewArray, 0);    
        
                NewArray[i_Lenght - 1] = NewItem;    
        
                return NewArray;    
            }    
        }   
     

    and the calling code would do:

    int[] ints = { 0, 1 };  
    ints = DynArray.Append(ints, 2); 
  • 10/15/2009 6:44 AM In reply to

    Re: Clean ways to dynamically add inherited items to a list?

    LightStriker:
    I know data inside an array are pointer. From what I understand, arrays in C# are tables of pointers.
    But it's the first time I hear arrays are themselves pointers.


    Arrays in C# are tables of whatever type you define them as - either value types or reference types.

    int[] myIntArray - this is an array of value types, not pointers. But myIntArray itself is still a reference type.


    struct MyStruct;

    MyStruct[] myStructArray - this is an array of value types. myStructArray itself is still a reference type.


    class MyClass;

    MyClass[] myClassArray - this is an array of reference types. myClassArray itself is still a reference type.


    Try not to compare things to C++ pointers, it will likely confuse. Try to understand C# reference types and value types properly.
Page 1 of 2 (32 posts) 1 2 Next > Previous Discussion Next Discussion