52

I have a table in my database that I use to manage relationships across my application. it's pretty basic in it's nature - parentType,parentId, childType, childId... all as ints. I've done this setup before, but I did it with a switch/case setup when I had 6 different tables I was trying to link. Now I have 30 tables that I'm trying to do this with and I would like to be able to do this without having to write 30 case entries in my switch command.

Is there a way that I can make reference to a .Net class using a string? I know this isn't valid (because I've tried several variations of this):

Type t = Type.GetType("WebCore.Models.Page");
object page = new t();

I know how to get the Type of an object, but how do I use that on the fly to create a new object?

thaBadDawg
  • 5,160
  • 6
  • 35
  • 44

6 Answers6

69

This link should help:
https://learn.microsoft.com/en-us/dotnet/api/system.activator.createinstance

Activator.CreateInstance will create an instance of the specified type.

You could wrap that in a generic method like this:

public T GetInstance<T>(string type)
{
    return (T)Activator.CreateInstance(Type.GetType(type));
}
Pang
  • 9,564
  • 146
  • 81
  • 122
Jason Miesionczek
  • 14,268
  • 17
  • 76
  • 108
  • 2
    This will not work if the assembly containing the type is not already loaded into the AppDomain. – Andrew Hare Feb 23 '09 at 17:31
  • 4
    Also in order to call that method then the OP must have access to the type at compile time - the original question asked how to create an instance at execution time from a string. – Andrew Hare Feb 23 '09 at 17:35
  • i am merely basing my answer on the example provided in the question. – Jason Miesionczek Feb 23 '09 at 17:35
  • Ah you are right - OP does appear to have access to the type! My mistake - (-1) removed! – Andrew Hare Feb 23 '09 at 17:37
  • Your example would require knowledge of the type at compile time as well :) – Jason Miesionczek Feb 23 '09 at 17:39
  • I get this error: "The type arguments for method 'GetInstance(string)' cannot be inferred from the usage. Try specifying the type arguments explicitly". If I'm specifying the type arguments, that kinda defeats the purpose of this. – Tod Oct 19 '17 at 11:12
  • One possible use case of this function is if you have an object hierarchy with an Interface as the root. You could specify the interface as the explicit type, and then pass in the concrete class that implements that interface as the function parameter. – Jason Miesionczek Oct 23 '17 at 11:45
14

If the type is known by the caller, there's a better, faster way than using Activator.CreateInstance: you can instead use a generic constraint on the method that specifies it has a default parameterless constructor.

Doing it this way is type-safe and doesn't require reflection.

T CreateType<T>() where T : new()
{
   return new T();
}
Judah Gabriel Himango
  • 58,906
  • 38
  • 158
  • 212
14
public static T GetInstance<T>(params object[] args)
{
     return (T)Activator.CreateInstance(typeof(T), args);
}

I would use Activator.CreateInstance() instead of casting, as the Activator has a constructor for generics.

Guillermo Perez
  • 589
  • 4
  • 10
AmuuuInjured
  • 141
  • 1
  • 2
9

You want to use Activator.CreateInstance.

Here is an example of how it works:

using System;
using System.Runtime.Remoting;

class Program
{
    static void Main()
    {
        ObjectHandle o = Activator.CreateInstance("mscorlib.dll", "System.Int32");

        Int32 i = (Int32)o.Unwrap();
    }
}
Andrew Hare
  • 344,730
  • 71
  • 640
  • 635
1

Here is a function I wrote that clones a record of type T, using reflection. This is a very simple implementation, I did not handle complex types etc.

 public static T Clone<T>(T original)
    {
        T newObject = (T)Activator.CreateInstance(original.GetType());

        foreach (var prop in original.GetType().GetProperties())
        {
            prop.SetValue(newObject, prop.GetValue(original));
        }

        return newObject;
    }

I hope this can help someone.

Assaf

Assaf S.
  • 4,676
  • 2
  • 22
  • 18
1

Assuming you have the following type:

public class Counter<T>
{
  public T Value { get; set; }
}

and have the assembly qualified name of the type, you can construct it in the following manner:

string typeName = typeof(Counter<>).AssemblyQualifiedName;
Type t = Type.GetType(typeName);

Counter<int> counter = 
  (Counter<int>)Activator.CreateInstance(
    t.MakeGenericType(typeof(int)));

counter.Value++;
Console.WriteLine(counter.Value);
sduplooy
  • 14,340
  • 9
  • 41
  • 60