15

This question already has an answer here:

Reading existing code at work, I wondered how come this could work. I have a class defined in an assembly :

[Serializable]
public class A
{
    private readonly string _name;
    private A(string name)
    {
        _name = name;
    }
}

And in another assembly :

public void f(Type t) {
    object o = Activator.CreateInstance(t);
}

and that simple call f(typeof(A))

I expected an exception about the lack of a parameterless constructor because AFAIK, if a ctor is declared, the compiler isn't supposed to generate the default public parameterless constructor.

This code runs under .NET 2.0.

[EDIT] I'm sorry but I misread the actual code... The sample I provided doesn't illustrate it. I accepted JonH answer because it provided a good piece of information.


  • @Codesleuth - it's been some time, sometimes remembering all these rules causes migranes. See below for answer. - JonH

4 답변


9

See this: Creating instance of type without default constructor in C# using reflection

Here's to the future also, this is in regards to C# 4.0:

Posted by Microsoft on 1/4/2010 at 2:08 PM
We have reviewed your bug and have determined that the behavior that you described is by design. We are now archiving this issue. Thanks for using Visual Studio and the .Net Framework!

There are many overloads of Activator.CreateInstance, the one that takes a single type parameter only invokes the default parameterless constructor. Constructors that take an optional parameter like the one in your example are not default constructors. To invoke them you need to:

  1. use an overload that takes an argument array
  2. Pass in Type.Missing as the argument
  3. Specify OptionalParamBinding in the BindingFlags

Here is an example:

Activator.CreateInstance(typeof(MyClassName),
 BindingFlags.CreateInstance |
 BindingFlags.Public |
 BindingFlags.Instance |
 BindingFlags.OptionalParamBinding,
 null, new Object[] {Type.Missing}, null);

Thanks,

Weitao Su

Microsoft Corp.


  • So maybe Seb has defined the class A elsewhere, or the assembly it is being loaded from is not being updated. It sounds like more of a project/solution problem rather than a code anomaly. - Codesleuth
  • @Codesleuth - quite possibly. - JonH

22

An alternative is:

object obj = System.Runtime.Serialization.FormatterServices
          .GetUninitializedObject(t);

which creates the object in memory but doesn't run any constructor. Scary.


  • That is quite scary, and exactly what I needed! +1 - ashes999
  • @ashes normally that is only used by seriaizers, proxies (RPC), orms, things like that - Marc Gravell
  • It worked on my simple test dll type var. but on the more complex dll with several classes, methods etc. your line crashed. An unhandled exception of type 'System.MemberAccessException' occurred in mscorlib.dll Additional information: Cannot create an abstract class. - humudu
  • @humudu yeah, you can't create abstract types even bypassing the constructor. That's simply not supported by the runtime. If you ever manage to create an abstract instance, something is very very broken. - Marc Gravell
  • I'd like to access and execute a runtime determined dll method in a seperate method from the one that loaded it in the first place. I tried here to convert it to an object property to access later, do you by any chance have a suggestion for it? - humudu

0

This may not be feasible for you to do, but the simplest thing is to pass the argument list after the type like so:

Activator.CreateInstance(t, "name");

You'll want to think about what f() is really trying to do. Should it be instantiating an object of type A at all? What other classes will it instantiate?

One possibility is to have a switch statement within f() which passes the correct parameters to CreateInstance() for class A. This won't scale, but that may not be an issue for you.


0

There are two confusing flavors of CreateInstance: one that takes an object of type System.Type as a parameter, another that takes a type parameter T.

First one:

object Activator.CreateInstance(type As Type) { }

Second one:

T Activator.CreateInstance<T>() { }

The second one is the one that doesn't work for a class without a public parameterless constructor.

Note that it almost never makes sense to even use the second one; in any case where it would be used, it would be better to have a where T : new() constraint on your class and simply use T's constructor.

The MSDN documentation agrees:

In general, there is no use for the CreateInstance in application code, because the type must be known at compile time. If the type is known at compile time, normal instantiation syntax can be used (new operator in C#, New in Visual Basic, gcnew in C++).

EDIT: I may have spoken too soon; it appears the first version isn't supposed to work either.


  • Yeah, first version throws the same error: No parameterless constructor defined for this object. - Evan

Linked


Related

Latest