views:

89

answers:

3

Probably simple but could not figure out. I am loading an assembly at runtime and browsing through some classes and generating input controls for its properties. To create an instance of an object at runtime I am using:

  object o =  PropertyType.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, null, Type.EmptyTypes,null).Invoke(null);

and it works fine for class types. When the type is an array, I use

  object o =  PropertyType.Type.GetConstructor(new Type[] { typeof(int) }).Invoke(new object[] { 0 });

which also works fine. But when it comes to string type or value types GetConstructor.Invoke does not work. I also tried Activator.CreateInstance which also did not work.

+5  A: 

What you're running into is that value types don't really have parameterless constructors. C# makes it look like they do, but they don't at the CLR level.

Activator.CreateInstance should work fine for real value types though:

object o = Activator.CreateInstance(typeof(int));
Console.WriteLine(o); // Prints 0

This will always give the default value for any value type.

Now, you're asking about strings - what string would you expect to create? The default value for the string type is null - but would you want the empty string instead? If so, you'll need to special-case that code.

Jon Skeet
Thanks Jon, I edited my question, Did not mean to say string is a value type... So how about string instantiation?
Erkan Y.
@Erkan: I've edited my answer. What string do you want to create? If you pick a constructor that actually exists, you can certainly invoke it with reflection - but of course you'll need to supply the values for the parameters...
Jon Skeet
@Jon, just want to instantiate a class property dynamically which is of type string, but I do not want the null value in the created object. So I guess I need to do special-case for string type properties in the class. Still not clear on how to create the object instance from a string type class property though. Since I will do a special-case would : if (property.PropertyType==typeof(string) ) object o = "" ; be sufficient?
Erkan Y.
@Erkan: Yes, that would do it. But is the default value for all other value types *really* useful? Can you give a bit more information about what you're going to do with the value? Maybe there's a better approach.
Jon Skeet
A: 

The int type doesn't have any constructors.

The code you write is going to depend on the property's type; normally, you'd write special-case code for string, int and other primitive types.

Your code above contains the literal 0; how do you decide what values to pass to the constructors?

Tim Robinson
A: 

If you want to be able to instantiate arbitrary objects with particular values, one thing you can check is if there is a TypeConverter that supports converting an instance (with the value you want to match) to an InstanceDescriptor. I'm not entirely sure what you're doing (your example suggests you're trying to create 'default' instances of the different objects), but just thought I'd mention this in case it's relevant. I use this in Emit code to emit arbitrary constant values to the stack via IL. Here's the snippet that gets the InstanceDescriptor:

        var converter = TypeDescriptor.GetConverter(value);
        if (converter.CanConvertTo(typeof (InstanceDescriptor)))
        {
            var desc = (InstanceDescriptor) converter.ConvertTo(value, typeof (InstanceDescriptor));

The descriptor specifies a means of constructing the instance, which could be calling a constructor, calling a static method, accessing a static property or accessing a static field. It also specifies whether the construction completely sets the value of the type to match your original instance; if not, you'll need to do additional reflection and setting of properties.

This is the mechanism that the WinForms Designer uses when generating the code-behind for the controls on the form, so it is supported for the common types that show up as properties of controls accessible from the designer.

Dan Bryant