Convert object to generic object in C# - c#

I have a list of generic objects:
private readonly List<object> _repositories = new List<object>();
Those object are all of type either "XmlRepository<T>" or "DbRepository<T>". I also have a generic Methods that returns me the first repository of generic type argument provided:
public IRepository<T> GetRepository<T>() where T : class {...}
I do also know what type argument should return XmlRepository<T> or DbRepository<T>:
var xmlTypeVar = typeof(XmlType);
var myXmlRepo = GetRepository<xmlTypeVar>()
but I don't know how to to convert it to the correctly typed object instance...
var myConvertedXmlRepo = myXmlRepo as XmlRepository<???>
What do I have to do here? The following is not possible:
var myConvertedXmlRepo = myXmlRepo as XmlRepository<xmlTypeVar> since I'm not allowed to provide a variable as generic type argument...
This example here is somehow simplicated, so it is not possible to me to replace the type variable (xmlTypeVar) with the dedicated Type itself.
Any help is highly appreciated! Thank you very much!

use reflection to create a generic type without knowing at compile time:
Type genericXmlRepositoryType= typeof(XmlRepository<>);
Type[] typeArgs = new[] { xmlTypeVar };
var generic = genericXmlRepositoryType.MakeGenericType(typeArgs);
As written in the comments, if you want to access a Method of XmlRepository<> after creating the dynamic instance, the best idea is to create a non-generic base class and call the method there:
XmlRepository repository = (XmlRepository)generic;
repository.UseTypeSpecificMethod();

Related

passing type of property to generic type

I have a generic class GenericClass<T>
for some reason I need to pass the generic type from another type like that:
say I have some classes from NormalClass1 to NormalClassN all of them have property say prop1 with different types
I need to do this
var type1 = typeof(NormalClass1).GetProperty("prop1").GetType();
and send type1 to new instance of GenericClass like that:
var instance = new GenericClass<type1>();
but an error has occurred that says that
Cannot implicitly convert type 'GenericClass<type1>' to 'GenericClass<T>'
how can I pass this type to GenericClass
There are multiple problems with your code.
First of all:
var type1 = typeof(NormalClass1).GetProperty("prop1").GetType();
will return the type PropertyInfo, not the type of the property. What you want is:
var type1 = typeof(NormalClass1).GetProperty("prop1").PropertyType;
Second of all you seem to have a conceptual issue with Generics, Types and TypeParameters.
Basically there is a difference between a Type variable (Type x = typeof(NormalClass1<>) and a generic Type parameter (the T in NormalClass<T>).
T is not much more than a placeholder for a Type. You can use typeof(T) to get the actual Type of T. Using typeof(x) on the other hand would result in a compulation error since x is a variable and not a Type. You would use x.GetType() instead.
You cannot create a generic type via a runtime type variable directly.
What you can do instead is creating the generic type via reflection.
The following example should illustrate how to do that
var genericTypeParameter = typeof(NormalClass1).GetProperty("prop1").PropertyType;
var genericBaseType = typeof(GenericClass<>);
var genericType = genericBaseType.MakeGenericType(genericTypeParameter);
var instance = Activator.CreateInstance(genericType);
As you can see, var instance would substitute to object instance. That has to be that way, since you can check the type of compile time. Best Practice would probably be to create a non generic base class for you generic class. You can than use the base class type and have at least a small amount of type checking at runtime, even if you have no chance to test the generic type parameter.
This would be what it would look like:
var instance = (GenericClassBase)Activator.CreateInstance(genericType);
You can only do it with Reflection:
var generic = typeof (GenericClass<T>).MakeGenericType(type1);
var instance = Activator.CreateInstance(generic);

Type with a generic where the type passed as a generic also has a generic causes an ArgumentException

I'm trying to create an instance of a type with a generic where the type passed as a generic also has a generic.
The following code is where the problem occurs:
internal virtual RouteBase GetRoute(DbContextTypeProvider databaseContextTypeProvider, Type model)
{
Type catchallRoute = typeof(CatchallRoute<,>);
catchallRoute.MakeGenericType(new Type[] {
databaseContextTypeProvider.DbContextType,
model
});
Type routeTypeWrapper = typeof(RouteTypeWrapper<>);
routeTypeWrapper.MakeGenericType(new Type[] {
catchallRoute
});
RouteTypeProvider routeTypeProvider = (RouteTypeProvider)Activator.CreateInstance(routeTypeWrapper);
return GetRoute(databaseContextTypeProvider, model, routeTypeProvider);
}
I based the code around what can be seen in the following SO question, when I use one type requiring generics in the same way as shown in the accepted answer the instance can be created, but the type requires a type with generics I just can't seem to get this working:
Pass An Instantiated System.Type as a Type Parameter for a Generic Class
I can't find any examples on MSDN showing how to create an instance of a type with generics where one of the generics it requires also requires generics.
If I code it so that the types are closed it would look like the following:
RouteTypeWrapper<CatchallRoute<SapphireDbContext<SiteTree>,SiteTree>> routeTypeProvider = new RouteTypeWrapper<CatchallRoute<SapphireDbContext<SiteTree>,SiteTree>>();
This is effectively what I'm trying to do but using reflection so that arguments can be passed to a method so that an instance can be created and returned.
But when I use reflection I get the following error:
Cannot create an instance of Sapphire.Cms.Web.Routing.RouteTypeWrapper`1[TRoute] because Type.ContainsGenericParameters is true.
Is what I'm trying to do possible and if so how can I correct the code so that it works?
MakeGenericType returns a new type. It does not modify the existing type. Change your code as below to get the result of MakeGenericType
internal virtual RouteBase GetRoute(DbContextTypeProvider databaseContextTypeProvider, Type model)
{
Type catchallRoute = typeof(CatchallRoute<,>).MakeGenericType(new Type[] {
databaseContextTypeProvider.DbContextType,
model
});
Type routeTypeWrapper = typeof(RouteTypeWrapper<>).MakeGenericType(new Type[] {
catchallRoute
});
RouteTypeProvider routeTypeProvider = (RouteTypeProvider)Activator.CreateInstance(routeTypeWrapper);
return GetRoute(databaseContextTypeProvider, model, routeTypeProvider);
}
Here is simple example showing how to do that.
class A<T>{}
class B<T>{}
class C<T>{}
...
var atype = typeof(A<>).MakeGenericType(new [] { typeof(int) });
var btype = typeof(B<>).MakeGenericType(new [] { atype });
var ctype = typeof(C<>).MakeGenericType(new [] { btype });
var cinstance = Activator.CreateInstance(ctype);

Create an instance of a custom generic class and a type stored in file as String

I am trying to create an instance of a generic class but my Type T of the generic class, i have gone through this link
http://msdn.microsoft.com/en-us/library/w3f99sx1(v=vs.110).aspx
but i couldn't find what i was looking for
i have this code
public class MyClass<T>
{
public T prop { get; set; }
}
and i have the type stored in string
the type
string typeString = "System.String";
now i want to use this type in myclass this way
Type xt = new Type.GetType(typeString);
MyClass<xt> obj = new MyClass<xt>();
but that just unidentified type xt
so what do i do!
The section Constructing an Instance of a Generic Type in the link provided covers this exact case.
In your case you would need write
Type typeArgument = Type.GetType(typestring);
Type constructed = typeof(MyClass<>).MakeGenericType(typeArgument);
object instance = Activator.CreateInstance(constructed);
However, the use cases of this techniques are far from common. You should try as much as possible to provide type information at compile-time. That is, try not to rely on Reflection to create your objects. Generics methods are especially useful for such cases.
The method Type.GetType(someString) gets the type at runtime, but generics class must be evaluated at compiled time. Between the <> symbols you need to specify the type itself and not an instance of the object Type. Something like this must work:
MyClass<String> obj = new MyClass<String>();
Thanks,

Compile-Time Generic Type Mapping without Reflection

In C#, is there any way to map one generic type to another generic type during compile time? I'd like to avoid using Reflection for this question. For example, let's say I would like to have TypeA map to TypeB, and have something similar to the following code work:
private void List<U> GetItemList<T>() where T : class <== U is the destination type obtained by the compile-time mapping from T to U
{
Type U = GetMappedType(typeof(T)) <=== this needs to happen during compile-time
List<U> returnList = Session.QueryOver<U>().List();
return returnList;
}
private Type GetMappedType(Type sourceType)
{
if (sourceType == typeof(TypeA))
return typeof(TypeB);
}
I realize that since I'm using a method call to map the type, that it will not do the mapping during compile time, but is there another way that accomplishes what I'm trying to achieve, only during compile time? I know that the code above is not correct, but I hope you can see what I'm trying to go for.
In short, I'd like to know if there's a way to map one type to another and have the C# compiler know the type mapping so that the destination type can be used as a Generic Type Parameter to any method that takes a Generic Type Parameter. I'd like to avoid using Reflection.
As a side-question, if I do use Reflection for this, will it make the implementation very resource-heavy?
Yes dynamic would be the answer. I had the same issue recently where I had to switch repositories based on some values configured in the database.
var tableNameWithoutSchema = tableName.Substring(tableName.IndexOf(".", StringComparison.Ordinal) + 1);
var tableType = string.Format("Library.Namespace.{0}, Library.Name", tableNameWithoutSchema);
var instance = UnitofWork.CreateRepository(tableType, uoW);
CreateRepository returns a dynamic type
public static dynamic CreateRepository(string targetType, DbContext context)
{
Type genericType = typeof(Repository<>).MakeGenericType(Type.GetType(targetType));
var instance = Activator.CreateInstance(genericType, new object[] { context });
return instance;
}
context was needed as I had to pass the context to Generic repository through constructor.
In my case this approach had some problems though.
May be this helps you.

Creating dynamic type collections and arrays

Lets say I have an interface passed to my method:
public void AlphaToChar(iList _blah)
{
}
Out of IList I want to extract it's members Type and use its type to create other Arrays or Lists in the method. See example below.
The "List = new List();" part doesn't work because, as I assume it's a type variable, not the actual type.
Any way around this ? How can I accomplish this and create a new collection of an extracted Type?
Type[] listTypes = list.GetType().GetGenericArguments();
Type listType = null;
if (listTypes.Length>0)
{
listType = listTypes[0];
}
List<listType> = new List<listType>();
Thank you.
You can do the List<> construction using the following:
// Find the generic argument type of your old list (theList)
Type genericType = theList.GetType().GetGenericArguments()[0];
// Create a new List with the same generic type as the old one
Type newListType = typeof(List<>).MakeGenericType(genericType);
// Create a new instance of the list with the generic type
var instance = Activator.CreateInstance(newListType);
But it's only going to work if you are using generic lists. The example you gave was using a regular IList. You would have to change your method signature to use a generic IList<>:
public void AlphaToChar(IList<Something> _blah) { }
Or make it even more generic:
public void AlphaToChar<T>(IList<T> _blah) /* where T : ISomething, new() */ {}
Without doing so, you should know what your IList is going to contain and you wouldn't have to use reflection to figure out what its elements types are.
This dynamically constructs a generic List<T> for the specified element type:
IList list = (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(elementType));
Note that the result variable is not statically typed to the specialized list, since you don't know the type at compile time. As such, it's not possible for it to be statically typed. You're taking advantage of the fact that List<T> also implements IList here.
System.Collections.IList list =
Activator.CreateInstance(typeof(List<>)
.MakeGenericType(listTypes[0])) as System.Collections.IList;

Categories

Resources