I have object of some type known at runtime and I read and deserialize this object from database. It works. Now I would like to add it to some list:
private static List<T> generateList<T>()
{
List<T> lst = new List<T>();
return lst;
}
private void readObjects(System.Type objType)
{
var methodInfo = typeof(My.Serializator).GetMethod("DeserializeDb");
var genericMethod = methodInfo.MakeGenericMethod(objType1);
List<curType> currentList= generateList<curType>();
// ...read stream from database and convert it to object
while (_rs.Read())
{
var _objItem = genericMethod.Invoke(null, new[] { _streamedData });
currentList.Add(_objItem);
}
}
It won't work. The error is:
curType is a variable but is used like a type.
If I change list to:
List<object> currentList = new List<object>();
it will work. But can i do this with generics(T) instead of object type?
You can easly create type of list you want via Activator, then cast to IList and use it:
private IList readObjects(System.Type objType)
{
var listType = typeof(List<>).MakeGenericType(curType);
var list = (IList)Activator.CreateInstance(listType);
// ...
while (_rs.Read())
{
// ...
list.Add(_objItem);
}
}
list will be instance of List<YorActualType>.
Update
When you declaring your method with generic arguments, it assumes you provide type info during compile time. Otherwise you need to use reflection.
Since you providing type info in run time (curType can hold any type info), compiler does not know what exactly type will be used, and you cannot declare your method to return something concrete. Only abstractions allowed.
Let's me show it on slightly insane but demonstrative example:
var types = new [] { typeof(int), typeof(string) };
var rand = new Random();
var list = readObjects(types[rand.Next(0,2)];
Until the very last moment even you will not know what exactly type of list will be created. Compiler does not know too. Compiler will never know what exactly type should be used if you not provide him with you types. When you use Type it only tells compiler that some regular parameter with type Type will be passed into the method in run time. There is no data to infer a type during compile time. That data can be passed only via generic type parameters.
So, there is several ways you can follow:
Provide exact types you need at compile time
private List<T> readObjects<T>()
{
var objType = typeof(T);
var list = new List<T>();
// rest of code....
}
Use reflection and base types
private IList readObjects(Type objType)
{
// rest of code with Activator and so on
}
And later usage depends on your needs.
If you know what type you going to use, simply convert:
var list = (IList<MyType>)readObjects(typeof(myType));
But I guess in that case better use way #1 with generic argument.
Otherwise you going to use reflection. Or some base classes, interfaces and so on. It depends on what exactly task you going to solve.
P.S. You can read more about generic types on MSDN.
Related
Code example:
void Foo(params object[] objects)
{
var entries = new List<IEntry>();
foreach(var o in objects)
{
var entry = new Entry<o.GetType()>(); // this doesn't work
entries.Add(entry);
}
...
}
Foo("hello", 5); // should fill entries with Entry<string> and Entry<int>
Why is that not possible? I guess I need to work with reflection instead? How to do that properly AND performant?
You just can't use C# generics the way you're trying to do in your snippet.
In order to use [C#] generics, the actual object type must be known at compile time.
You're trying to dynamically pass the object type as a type parameter. This is simply not possible.
Edit
Yes, it is possible to dynamically create generic objects using reflection. After all, generics is implemented both as a compile-time C# construct and as a .NET framework feature (as opposed to, say, Java, where it is only a compile-time feature based on Type Erasure). So, in .NET, through reflection, it is possible to implement the latter "bypassing" the former (which, again, would be impossible in Java).
But the OP clearly does not need that.
After all, entries is a List<IEntry>. IOW, the entries container does not "know" the concrete type of its elements (since it is bound to an interface). So, if each element to be add already implements IEntry, then this would be enough:
void Foo(params IEntry[] objects)
{
var entries = new List<IEntry>();
foreach(var o in objects)
{
entries.Add(o);
}
...
}
OTOH, if those objects do not implement IEntry, then the OP just need a pure, ordinary, old-school list of untyped objects:
void Foo(params object[] objects)
{
var entries = new List<object>();
foreach(var o in objects)
{
entries.Add(o);
}
...
}
So using reflection in order to dynamically create a generic container, even if possible, seems to be overkill for this particular use case.
You can do it with reflection
var entryType = typeof(Entry<>);
Type[] typeArgs = { o.GetType() };
var genericType = entryType.MakeGenericType(typeArgs);
IEntry entry = (IEntry)Activator.CreateInstance(genericType);
You need a function of the form:
Func<Type, IEntry>
I would suggest adding a static function to the parent of Foo like this:
public static IEntry Make(Type type)
Inside that function, feel free to add whatever code makes sense to you:
if (type == typeof(string))
{
return new StringEntry(); //Obviously some special logic based on the type.
}
else
{
//Default logic
return (IEntry) Activator.CreateInstance(typeof(Entry<>).MakeGenericType(type));
}
Given
int foo = 1;
Type unboundType = typeof(List<>);
Type w = unboundType.MakeGenericType(typeof(int));
if (w == typeof(List<int>))
{
Console.WriteLine("Yes its a List<int>");
try
{
((List<int>)(object)w).Add(foo);
}
catch(InvalidCastException)
{
Console.WriteLine("No you can't cast Type");
}
}
I can verify that the type indeed matches a constructed type and perform an action based on said constructed type. However, I cannot cast Type to it's class using as or an explicit cast. Is there a practical purpose for allowing developers to create a Type of unbound type or does this functionality exist solely to support the language in some way?
Not everything can be done at compile time. Sometimes, particularly in library code, you need to take what you are given. In scenarios where you are given just an object or a Type and need to do some clever processing, unbound types can be really helpful; for example:
object obj = NoIdeaWhatThisReturns();
IList list = (IList)Activator.CreateInstance(
typeof(List<>).MakeGenericType(obj.GetType()));
list.Add(obj);
Basically; scenarios that use a lot of reflection or meta-programming will probably find themselves using unbound types at some point.
In the code you posted, you didn't actually instantiate an object of that type anywhere. You were simply trying to cast an instance of System.Type to List<int> which doesn't make sense. If you update your code to actually create an instance, it works:
int foo = 1;
Type unboundType = typeof(List<>);
Type w = unboundType.MakeGenericType(typeof(int));
if (w == typeof(List<int>))
{
Console.WriteLine("Yes its a List<int>");
object obj = Activator.CreateInstance(w);
try
{
((List<int>)obj).Add(foo);
Console.WriteLine("Success!");
}
catch(InvalidCastException)
{
Console.WriteLine("No you can't cast Type");
}
}
Maybe I'm just missing the crux of your question. Certainly depending on your logic, you could have if/else checks based on some type you don't know at compile time (in your example, you know you're working with int, but perhaps at runtime that could be other types as desired)
EDIT: Just to provide an example of a truly runtime usage, consider the following:
public object CreateList(Type elementType, object initialValue)
{
if (!elementType.IsAssignableFrom(initialValue.GetType()))
throw new ArgumentException("Incompatible types!");
Type unboundType = typeof(List<>);
Type listType = unboundType.MakeGenericType(elementType);
object list = Activator.CreateInstance(listType);
var addMethod = listType.GetMethod("Add");
addMethod.Invoke(list, new []{initialValue});
return list;
}
This lets us create a List<T> out of some unknown type/object at runtime. Some usage:
object intList = CreateList(typeof(int), 1);
object stringList = CreateList(typeof(string), "asdf");
object objectFromSomewhere = GetMyUnknownObject();
object someUnknownListType = CreateList(objectFromSomewhere.GetType(), objectFromSomewhere);
So, you might not be able to do much with the objects as are; probably could have treated them as IEnumerable at least. But that's up to what your system needs to do.
EDIT: Forgot about the IList interface:
public IList CreateList(Type elementType, object initialValue)
{
if (!elementType.IsAssignableFrom(initialValue.GetType()))
throw new ArgumentException("Incompatible types!");
Type unboundType = typeof(List<>);
Type listType = unboundType.MakeGenericType(elementType);
IList list = (IList)Activator.CreateInstance(listType);
list.Add(initialValue);
return list;
}
Type is not a placeholder for a given type - it's a specific type itself to describe other types. There's no point in trying cast it to a different, unrelated type because metadata (obviously) cannot act for that specific type.
The metadata types are used to inspect the various aspects of specific types, not to create one. If you want to create instances of types in a generic way, you can use the Activator class for that.
Type oType = ...; // get a Type instance here about a type
object[] oArgs = { oParam1, oParam2 }; // constructor parameters (if any)
return ( Activator.CreateInstance ( oType, oArgs ) );
This gives you the ability to create types based on strings, for example. You can get a Type instance for System.String (or from a function call like GetTypeNameFromUser(...)) and then create an instance of that type. (Activator has direct support for just taking a string but internally, it uses Type to look up the type that needs to be instantiated.)
Since all types are equal, you can create a Type instance for an unbound generic type just like any other type - at the very least, it allows you to inspect its properties and methods. (As the accepted answer shows, you can also use the Type instance to create specialized generic types using MakeGenericType.)
[TestMethod]
public void TestMyGenericBaseClasses()
{
Type typeCrazy = ThisPartyIsTypeCrazyWOOT();
// How do I create a generic object?
MadnessOhYeah<typeCrazy> sanity = new MadnessOhYeah<typeCrazy>();
// How do I use a generic object after it has been created?
Assert.IsTrue(sanity.MyTrueFunction(), "this is sparta");
// How do I call a generic function generically?
bool result = MyFunction<typeCrazy>();
Assert.IsTrue(result, "I did not get my teeth whitened!");
}
Is there any way to make this compile? (ThisPartyIsTypeCrazyWOOT returns a Type) Because this is a test, we're not concerned about having to use reflection or anything, unless that's just absolutely crazy.
I'm getting the vibe that this isn't going to be possible though, and that our test functions will just have to be more specific.
You need Type.MakeGenericType Method. Then Activator.CreateInstance Method.
Update 2: The first example I posted still doesn't 100% answer the question, since it involves a cast to List<int>, which is a type that is known at compile time. Below is a reflection-only solution that illustrates how you can use a generic type knowing nothing about the type argument itself. But, as you can see, it's... well, disgusting ;)
Type userType = GetUserSuppliedType();
// Now let's say userType is T.
// Then here we are getting the type typeof(List<T>).
// But, of course, there's no way to have any such information in the code.
Type listOfUserType = typeof(List<>).MakeGenericType(new[] { userType });
// This is effectively calling new List<T>();
object listObject = Activator.CreateInstance(listOfUserType);
// Do you see how messy this is getting?
MethodInfo addMethod = listOfUserType.GetMethod("Add");
// We better hope this matches userType!
object input = GetUserSuppliedInput();
// I suppose we could check it, to be sure...
if (input == null || input.GetType() != userType)
{
throw new InvalidOperationException("That isn't going to work!");
}
// Here we are finally calling List<T>.Add(input) -- just in the most ass-
// backwards way imaginable.
addMethod.Invoke(listObject, new[] { input });
Update: OK, if you insist on doing this, here's an example of how it's possible—but very cumbersome!
Type genericListType = typeof(List<>);
Type listOfInt32Type = genericListType.MakeGenericType(new[] { typeof(int) });
object listObject = Activator.CreateInstance(listOfInt32Type);
List<int> list = (List<int>)listObject;
list.Add(1);
Generics can't quite work like this because a Type object could be anything. Consider this code:
var list = new List<int>();
list.Add(1);
The type of list in the above code is known to be List<int>, which defines what operations are legal on list such as Add(1).
Now consider this instead:
Type t = GetTypeFromIndeterminateSourceSuchAsUserInput();
var list = new List<t>();
list.Add(?);
When t is a Type object rather than the name of a type (like int) which the compiler can parse, it's not really possible to instantiate a generic type using that type—or rather, it's possible (see Andrey's answer), but you can't really use the resulting object in any sort of generic way.
Now, you might think that something like this ought to work:
Type t = typeof(int);
var list = new List<t>();
list.Add(1);
...but just because the value of t is known (by you) at compile time doesn't change the way things work in general.
Anyway, yes it's possible using reflection; but if you go down that path, you're committing to a pretty reflection-heavy solution. What I'm getting at is that in general it isn't a particularly realistic thing to do.
I am trying out a little reflection and have a question on how the cast the result object to an IList.
Here is the reflection:
private void LoadBars(Type barType)
{
// foo has a method that returns bars
Type foo = typeof(Foo);
MethodInfo method = foo.GetMethod("GetBars")
.MakeGenericMethod(bar);
object obj = method.Invoke(foo, new object[] { /* arguments here */ });
// how can we cast obj to an IList<Type> - barType
}
How can we cast the result of method.Invoke to an IList of Type from the barType argument?
The point of a cast is usually to tell the compiler that you have some extra information - that you know something at compile time. You don't know that information here - you only know it at execution time.
What would you expect to do with the value after casting it? Admittedly there are some times when it would be useful - when you've got to use a generic interface, even if you want to get at members which don't require the type parameter (e.g. Count in IList<T>). However, if that's not what you're trying to do it would really help if you could give more information.
I've just finished wrestling with this problem.
True, you cannot cast the object into a Generic IList but you can convert it into a strongly typed Array by invoking the "ToArray" method of the List object.
Solution pilfered from another blog.
http://amazedsaint.blogspot.com/2008/04/creating-generic-list-at-runtime.html
ToArrayMethod = obj.GetType().GetMethod("ToArray");
System.Array stronglyTypedArray=(System.Array) ToArrayMethod.Invoke(obj,null);
In .NET 4.0 you can use expression trees to achive that.
private void LoadBars<T>()
{
Type barType = typeof(T);
// foo has a method that returns bars
Type foo = typeof(Foo);
MethodInfo method = foo.GetMethod("GetBars")
.MakeGenericMethod(bar);
IList<T> obj = (IList<T>)method.Invoke(foo, new object[] { /* arguments here */ });
}
Casting would only make sense if the caller of your function new barType at compile time, and not a runtime. And once that is true, you could just template the function to:
private IList<T> LoadBars<T>()
{
...
return obj as IList<T>;
}
This question already has answers here:
How do I use reflection to call a generic method?
(8 answers)
Closed 9 years ago.
Is it possible to declare an instance of a generic without knowing the type at design-time?
Example:
Int i = 1;
List<typeof(i)> list = new List<typeof(i)>();
where the type of i could be anything, instead of having to do:
List<int> list = new List<int();
If you don't know the type at compile-time, but you want the actual type (i.e. not List<object>) and you're not in a generic method/type with the appropriate type parameter, then you have to use reflection.
To make the reflection simpler, I've sometimes introduced a new generic type or method in my own code, so I can call that by reflection but then just use normal generics after that. For example:
object x = GetObjectFromSomewhere();
// I want to create a List<?> containing the existing
// object, but strongly typed to the "right" type depending
// on the type of the value of x
MethodInfo method = GetType().GetMethod("BuildListHelper");
method = method.MakeGenericMethod(new Type[] { x.GetType() });
object list = method.Invoke(this, new object[] { x });
// Later
public IList<T> BuildListHelper<T>(T item)
{
List<T> list = new List<T>();
list.Add(item);
return list;
}
Of course, you can't do an awful lot with the list afterwards if you don't know the type... that's why this kind of thing often falls down. Not always though - I've used something like the above on a few occasions, where the type system just doesn't quite let me express everything I need to statically.
EDIT: Note that although I'm calling Type.GetMethod in the code above, if you were going to execute it a lot you'd probably want to just call it once - after all, the method isn't going to change. You may be able to make it static (you could in the case above) and you probably want to make it private too. I left it as a public instance method for the simplicity of the GetMethod call in sample code - you'd need to specify the appropriate binding flags otherwise.
If you don't know the type at design-time, I'd say you have a list of OBJECTS (the base class for all other types).
List<object> list = new List<object>();
I think the best you are going to be able to do is something like this:
static void Main(string[] args)
{
int i = 1;
var thelist = CreateList(i);
}
public static List<T> CreateList<T>(T t)
{
return new List<T>();
}
You can also use Activator.CreateInstance. Example code snippet:
public class BaseRepository<T> where T : DataContext
{
protected T _dc;
public BaseRepository(string connectionString)
{
_dc = (T) Activator.CreateInstance(typeof(T), connectionString);
}
public void SubmitChanges()
{
_dc.SubmitChanges();
}
}
If you still want to type .Add(), .Remove(), do foreach etc. you can treat the List as a regular "old" System.Collections.IList,
since this interface is luckily implemented by List<T>.
And since all other posted answers to this question shows pretty much every other possible way to create an instance of a List<T> dynamically,
i will show one last way to do it.
I personally use this method when creating generic instances, when i don't really know nothing about the type at compile time,
and the type must be passed as a string, perhaps coming from the application configuration file.
In this example, T is System.String for simplicity but it could be anything:
Type T = typeof ( string ); // replace with actual T
string typeName = string.Format (
"System.Collections.Generic.List`1[[{0}]], mscorlib", T.AssemblyQualifiedName );
IList list = Activator.CreateInstance ( Type.GetType ( typeName ) )
as IList;
System.Diagnostics.Debug.Assert ( list != null ); //
list.Add ( "string 1" ); // new T
list.Add ( "string 2" ); // new T
foreach ( object item in list )
{
Console.WriteLine ( "item: {0}", item );
}