[Webinar] Streamline your web hosting managementRegister Today

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1992
  • Last Modified:

Reflection, Activator.CreateInstance, array<T>

In a generic filer class which knows nothing about the calling assembly's data structures except through reflection, I need to create an instance of a List<T>. I can create simple instances (ints, strings, class instances etc) but not arrays, for two reasons:
1. I can use Assembly.GetType(typeName) to get a Type but if the calling assembly's property is defined as List<ofSomething> then the PropertyInfo.PropertyType.Name is "List`1" - not something nice like TheNameOfMyClass.
2. This might not actually be a problem but since I can't solve #1, I have no idea whether this works! I create an instance using Activator.CreateInstance(objType, numItems). Is this correct to initialise a collection to a known number of elements before later calling pinfo.SetValue(item, reference, index)?
Code used to create list:
Type objType = assembly.GetType(assembly.GetName().Name + "." + pinfo.PropertyType.Name, true);
object objInstance = Activator.CreateInstance(objType, numItems);

assembly - Assembly in which to look for type name
pinfo - PropertyInfo of the property
numItems - size of the array/collection

Example class being populated by reflection:
class MyClass
{
  public string TestString;
  public int TestInt;
  public bool TestBool;
  public List<string> TestList;
}
The string/int/bool work fine (different code from above) but the list doesn't. I can't change the List<string> definition.

Open in new window

0
gmayo
Asked:
gmayo
  • 2
1 Solution
 
gmayoAuthor Commented:
Actually I can get that to work if the list is declared as a "proper" class, ie:
class MyList : List<MyType>

I'd still like to solve problem #1 if I can though.

However, I now have a problem adding items to that list:

objInstance[idx++] = childInstance;
// obviously doesn't work because objInstance is of type object.

(object[])objInstance[idx++] = childInstance;
// also doesn't work - runtime error casting from object[] to List<MyType>

(List<object>)objInstance[idx++] = childInstance;
// also doesn't work for the same reason. I'm out of ideas now!

Open in new window

0
 
PockyMasterCommented:
@2 : if you create a list with the number of items constructor, you're not actually creating the items, but only reserving that amount of memory.

if you want to do something with the list, but you have problems accessing its members, do something like:
object objInstance = Activator.CreateInstance(objType, numItems);  // your code

IList myList = objInstance as IList;

if (myList != null)
{
   myList.Add(childinstance); // add the child item
}
0
 
mikebirtCommented:
Hi,

I'm not sure i fully understand what you're doing in your question, however it appears you're having difficulty creating a generic collection driven by some reflection activities? It might help to use the MakeGenericMethod which allows you to interact with your collection exactly as you'd want to but to provide the type parameter dynamically.

I've put together a short code example, it's fairly dirty stuff, but it illustrates the idea, all be it with some undesireable string handling to retrieve the collection's 'collected' type.

HTH

Mike
public class AnotherClass
        {
            public int MyNumber { get; set; }
        }

        public class MyClass
        {
            public int TestInt;
            public bool TestBool;
            public List<AnotherClass> TestList;
        }

        private void Populate()
        {
            Type theType = typeof(MyClass);
            FieldInfo[] fields = theType.GetFields();
            object myObj = Activator.CreateInstance(theType);

            foreach (FieldInfo fi in fields)
            {
                if (fi.FieldType.Name == "List`1")
                {
                    string s = fi.FieldType.AssemblyQualifiedName;
                    s = s.Replace("System.Collections.Generic.List`1[[", string.Empty);
                    s = s.Substring(0, s.IndexOf("]"));

                    Type listType = Type.GetType(s);
                    MethodInfo mi = this.GetType().GetMethods(BindingFlags.Instance | BindingFlags.NonPublic)
                                                    .Where(m => m.IsGenericMethod && m.Name.StartsWith("BuildList")).First();

                    mi = mi.MakeGenericMethod(new Type[] { listType });
                    object theList = mi.Invoke(this, new object[0]);

                    fi.SetValue(myObj, theList);
                }
                else
                {
                    fi.SetValue(myObj, Activator.CreateInstance(fi.FieldType));
                }
            }
        }

        private List<T> BuildList<T>() 
        {
            int numOfObjects = 5;
            List<T> mList = new List<T>();

            for (int iLoop = 0; iLoop < numOfObjects; iLoop++)
            {
                mList.Add((T)Activator.CreateInstance(typeof(T), null));
            }

            return mList;
        }

Open in new window

0
 
gmayoAuthor Commented:
Thanks - I'm aware I was only reserving space in the array, not actually creating the contents. My intention was to set each index, rather than Add()ing items, and specifying the size first was the idea to avoid out of range exceptions. However, that was flawed anyway.
0

Featured Post

The new generation of project management tools

With monday.com’s project management tool, you can see what everyone on your team is working in a single glance. Its intuitive dashboards are customizable, so you can create systems that work for you.

  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now