18

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.

NotAPro
  • 136
  • 2
  • 17
Jordan
  • 2,708
  • 4
  • 22
  • 35
  • How is the property (the one of type `System.Collections.Generic`) declared in your C# code? Is its type argument `` the same as that of the `GenericRepository` that owns the property? – Sergey Kalinichenko Jan 23 '12 at 00:23
  • 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 – Jordan Jan 23 '12 at 00:36
  • So is the property in the `Teacher` class declared as `List Classes {/*getter and/or setter*/}`? Wouldn't `Activator.CreateInstance(Property.GetType())` work then? – Sergey Kalinichenko Jan 23 '12 at 00:45
  • 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 – Jordan Jan 23 '12 at 01:04
  • Both answers below are correct then. Did they work for you? – Sergey Kalinichenko Jan 23 '12 at 01:07
  • 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 Jan 23 '12 at 01:21

2 Answers2

45

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);
Thomas Levesque
  • 286,951
  • 70
  • 623
  • 758
  • 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 and I do ?((GenericRepository)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. – Jordan Jan 23 '12 at 02:01
  • @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` class. Or you could call the method dynamically using reflection, but it's slower... – Thomas Levesque Jan 23 '12 at 08:39
4
Activator.CreateInstance(typeof(GenericRepository<>).MakeGenericType(new Type[] { Property.GetTYpe() }))
sblom
  • 26,911
  • 4
  • 71
  • 95