c# Creating an unknown generic type at runtime

23,350

Solution 1

I think you're looking for the MakeGenericType method:

// Assuming that Property.PropertyType is something like List<T>
Type elementType = Property.PropertyType.GetGenericArguments()[0];
Type repositoryType = typeof(GenericRepository<>).MakeGenericType(elementType);
var repository = Activator.CreateInstance(repositoryType);

Solution 2

Activator.CreateInstance(typeof(GenericRepository<>).MakeGenericType(new Type[] { Property.GetTYpe() }))
Share:
23,350
Jordan
Author by

Jordan

I was a software developer for UPS in another life [1999-2001]. I quit to get my degree in Software Engineering and Psychology I really enjoy developing software. Especially database driven things. Currently a bit over my head making a site using ASP.NET/C#, XML, XSLT, javascript/ajax/json, SQL 2008R2. It is my passion to create things that are extremely fast and efficient despite the fact that the solutions might not be simple.

Updated on July 09, 2022

Comments

  • Jordan
    Jordan almost 2 years

    So I have a class that is a generic and it may need to, inside a method of its own, create an instance of itself with a different kind of generic, whose type is obtained through reflection.

    This is important because this Repository maps T to a database table [it's an ORMish I am writing] and if the class that represents T has a collection representing ANOTHER table I need to be able to instance that and pass it to the repository [ala Inception].
    I'm providing the method in case it makes it easier to see the problem.

    private PropertiesAttributesAndRelatedClasses GetPropertyAndAttributesCollection() 
    {
      // Returns a List of PropertyAndAttributes
    
      var type = typeof(T);
      //For type T return an array of PropertyInfo
    
      PropertiesAttributesAndRelatedClasses PAA = new PropertiesAttributesAndRelatedClasses();
      //Get our container ready
    
      //Let's loop through all the properties.
      PropertyAndAttributes _paa;
      foreach(PropertyInfo Property in type.GetProperties())
      {
        //Create a new instance each time.
        _paa = new PropertyAndAttributes();
    
        //Adds the property and generates an internal collection of attributes for it too
        _paa.AddProperty(Property);
    
        bool MapPropertyAndAttribute = true;
        //This is a class we need to map to another table
        if (Property.PropertyType.Namespace == "System.Collections.Generic")
        {
          PAA.AddRelatedClass(Property);
          //var x = Activator.CreateInstance("GenericRepository", Property.GetType().ToString());
        }
        else 
        {
          foreach(var attr in _paa.Attrs) 
          {
            if (attr is IgnoreProperty)
            {
              //If we find this attribute it is an override and we ignore this property.
              MapPropertyAndAttribute = false;
              break;
            }
          }
        }
        //Add this to the list.
        if (MapPropertyAndAttribute) PAA.AddPaa(_paa);
      }
      return PAA;
    }
    

    So given GenericRepository<T>, and I want to make a GenericRepository<string type obtained via reflection from the Property> how would I do this? The line I need to replace with something that WORKS is:

    //var x = Activator.CreateInstance("GenericRepository", Property.GetType().ToString());
    

    Thanks.

    • Sergey Kalinichenko
      Sergey Kalinichenko over 12 years
      How is the property (the one of type System.Collections.Generic) declared in your C# code? Is its type argument <T> the same as that of the GenericRepository<T> that owns the property?
    • Jordan
      Jordan over 12 years
      No, basically it is just a generic collection of another class as a property on a class. i.e. A Teacher class has a list of classes class. The repository gets the teacher class and has to also process the classes class, but since it is really getting T it has to figure out what it has to process using reflection
    • Sergey Kalinichenko
      Sergey Kalinichenko over 12 years
      So is the property in the Teacher class declared as List<Class> Classes {/*getter and/or setter*/}? Wouldn't Activator.CreateInstance(Property.GetType()) work then?
    • Jordan
      Jordan over 12 years
      ah but I need a REPOSITORY [my own generic] of type T where T = Classes if the currently instanced repository is T = Teachers. What you suggest would work but just to create the type Classes
    • Sergey Kalinichenko
      Sergey Kalinichenko over 12 years
      Both answers below are correct then. Did they work for you?
    • Jordan
      Jordan over 12 years
      Yes tested and both work. I +1 both but gave the best answer to the one that was easier to understand. Thank you both.
  • Jordan
    Jordan over 12 years
    If I may, I am running into 1 problem. I cannot access any methods for the given repository. If I access it via the immediate window where it made say GenericRepository<Locations> and I do ?((GenericRepository<DocerZocer.Models.Location>)repository)‌​.GetAll() This properly works, how can I cast it properly in the code such that I don't need this? Obviously I can only do it in the immediate window because I know the type it represents.
  • Thomas Levesque
    Thomas Levesque over 12 years
    @Jordan, you could create a non-generic IRepository interface with a GetAll method that returns an array of objects, and implement this interface explicitly in the GenericRepository<T> class. Or you could call the method dynamically using reflection, but it's slower...
  • Thomas Levesque
    Thomas Levesque over 12 years
    This will create an instance of GenericRepository<RuntimePropertyInfo>, since Property.GetType() returns RuntimePropertyInfo...