Instantiate an Object with a Runtime-Determined Type

Instantiate an object with a runtime-determined type

There are several ways you can create an object of a certain type on the fly, one is:

// determine type here
var type = typeof(MyClass);

// create an object of the type
var obj = (MyClass)Activator.CreateInstance(type);

And you'll get an instance of MyClass in obj.

Another way is to use reflection:

// get type information
var type = typeof(MyClass);

// get public constructors
var ctors = type.GetConstructors(BindingFlags.Public);

// invoke the first public constructor with no parameters.
var obj = ctors[0].Invoke(new object[] { });

And from one of ConstructorInfo returned, you can "Invoke()" it with arguments and get back an instance of the class as if you've used a "new" operator.

Instantiate generic class using runtime class of an object

Because of runtime type erasure, the runtime object created by MyClass<X> and MyClass<Y> will be identical. The fact that new MyClass<X>().myMethod() can be called on an X but not on a Y is a compile-time fact, not a run-time one. The compile-time question is "can it be called on this variable", not "can it be called on objects with the same result of getClass()".

You can create factory methods to create generic instances of your class based on the compile-time types of Class objects, or of the actual objects you wish to use it with:

public class MyClass<T> {
// ...

public static <T> MyClass<T> forClass(Class<T> c) {
return new MyClass<T>();
}

public static <T> MyClass<T> forObject(T object) {
return new MyClass<T>();
}
}

If you want your generic class's method to actually have runtime type checking, that's possible, too. Just store a Class object for the type in your MyClass instance, and use its isInstance() or cast() method to check the type of the argument to your method. You have to do this manually, because this is not what is usually done for ordinary generic classes, which is because it is usually unnecessary.

How to create/instantiate an object of 'Type'

Activator.CreateInstance is what you're after.

var tasks = new List<IScheduledTask>();
foreach (Type t in Assembly.GetExecutingAssembly().GetTypes())
{
if (t.IsSubclassOf(typeof(IScheduledTask)))
{
tasks.Add((IScheduledTask)Activator.CreateInstance(t));
}
}

How to instantiate a certain number of objects determined at runtime?

Just use a

List<Person> lstPersons = new List<Person>();

And then add persons to it with:

lstPersons.Add(new Person());

You can then access the persons with

lstPersons[0]
lstPersons[1]
...

Best way to create an instance of run-time determined type

You are looking for Activator.CreateInstance (there are also other overloads, such as this one that accepts constructor arguments). So you could write

var anotherOneLikeMe = Activator.CreateInstance(this.GetType());

There may be a problem here in that anotherOneLikeMe is going to be typed as object, so unless you intend to cast it to a common base class (e.g. BaseClass in your example) there's not much that you can do with it.

How do I build a Java type object at runtime from a generic type definition and runtime type parameters?

I think I understand your question. You want to serialize a Foo<T>, and you have the class object of T at runtime (but it's not fixed at compile time). Therefore, the suggested solution in Gson of creating an anonymous subclass of TypeToken does not work because that requires that the parameterized type (e.g. Foo<String>) be hard-coded at compile time, and it does not work if you use something like Foo<T>.

However, let's look at what the TypeToken method on the Gson site actually accomplishes. You create an object of an anonymous subclass of TypeToken, and then ask for its type parameter using its getType() method. A class's superclass is part of its metadata, and includes the generic parameters of its superclass. So at runtime, it can look at its own inheritance hierarchy, and figure out what type parameter you used for TypeToken, and then returns a java.lang.reflect.Type instance for that type (which, if it is parameterized, will be a ParameterizedType instance). Once you get this Type instance, you are supposed to pass it as the second argument of the toGson().

All we need to do is find another way to create this instance of ParameterizedType. ParameterizedType is an interface, but unfortunately the public Java API does not provide any concrete implementations or any way to create a ParameterizedType dynamically. There appears to be a class called ParameterizedTypeImpl, in the private Sun APIs and in the Gson code that you can use (e.g. here). You can simply copy the code and rename it into your own class. Then, to create a Type object representing Foo<String> at runtime, you can just do something like new ParameterizedTypeImpl(Foo.class, new Type[]{String.class}, null) (untested)

How to create a new object instance from a Type

The Activator class within the root System namespace is pretty powerful.

There are a lot of overloads for passing parameters to the constructor and such. Check out the documentation at:

http://msdn.microsoft.com/en-us/library/system.activator.createinstance.aspx

or (new path)

https://learn.microsoft.com/en-us/dotnet/api/system.activator.createinstance

Here are some simple examples:

ObjectType instance = (ObjectType)Activator.CreateInstance(objectType);

ObjectType instance = (ObjectType)Activator.CreateInstance("MyAssembly","MyNamespace.ObjectType");

Instantiating derived types in C++

What's the best way to do this?

You can't. If you declare a variable type as Base, the stack allocation for it will be suitable for holding an instance of Base but not an instance of a derived type (which might be larger, though even if it is not, you still cannot do what you ask; the runtime type of a variable in C++ is always the same as its declared type). At best, you could slice the derived instance into a Base-type variable.

The best bet is to use a pointer, optionally wrapped in a shared_ptr or unique_ptr to give you similar semantics (i.e. to have the object be automatically destroyed when it goes out of scope, assuming ownership hasn't been transferred).

Base* b = (condition) ? (Base *) new One() : new Two();
auto bptr = shared_ptr<Base>(b);

Note that what this gives you is effectively the same as the Java. The object itself is heap allocated, but the reference to it is stack allocated. Despite the syntax, a reference-type Java variable is essentially equivalent to a pointer in C++.

Can you instantiate a template class at runtime using C#

Yes, you can instantiate a generic class with a type known only at runtime, e.g.:

public class A { }
public class U<T> {
public T X { get; set; }
}

static void Main(string[] args) {
Type a = typeof(A);
Type u = typeof(U<>);
dynamic uOfA = Activator.CreateInstance(u.MakeGenericType(a));
uOfA.X = new A();
Console.WriteLine(uOfA.GetType());
Console.WriteLine(uOfA.X.GetType());
}

However, this snippet uses reflection and dynamic typing, both of which may cause a lot of maintenance problems, so you would be better off using them very carefully or finding a simpler solution.



Related Topics



Leave a reply



Submit