How do create a Generic Object using Reflection - c#

First let me say, that what I want to do is get the value of a property in a generic class that may be overriden by class that inherits from it. Think of it in the base class as a default value, that the inheritor of the class can override to set their own Default value.
I have tried to use reflection directly on the type, using the System.Reflection.FieldInfo.GetValue but this does not work for classes with generic types. So I think that I need to instantiate the class to be able to see what the value is.
The "types" I have I retrieved by reading the Dlls in the bin and using Reflection to find the types that inherit from my interface.
I am using .NET 4.5
here is documentation that seems like it explains exactly what I need to do
http://msdn.microsoft.com/en-us/library/b8ytshk6.aspx
In this documentation the only difference I can see is how we got our types, I looked in the bin for types and they simply called typeof(), Since types are so complex it seems this may be a likely mis-match but I cannot see what is missing(if anything)
foreach (var item in types)
{
var ts = item.GetField("DefaultTimeToExpire");
Type[] typeArguments = item.GetGenericArguments();
if (ts != null)
{
var t = item.MakeGenericType(typeArguments);
var obj = Activator.CreateInstance(t);
var timespan = obj.DefaultTimeToExpire;
subscriberInfos.Add(new Tuple<string, Type, TimeSpan>(item.Name, item, timespan));
}
}
I am calling GetField to look for Items that have a field "DefaultTimeToExpire" so far this part works well to find the type I need.
Next I call GetGenericArguments which returns an expected array of the type Arguments.
then I call MakeGenericType
and finally Create instance wich gives me the error message
"Cannot create an instance of BusinessLogic.TestSubscriberXXX`1[Message] because Type.ContainsGenericParameters is true."
This looks like exactly what I am supposed to do.
Thanks

In order to instantiate a generic type, you need to know the actual values (types) that should be substituted for its type parameters. The GetGenericArguments() method, being a form of reflection, only gives you the type arguments, not their actual values. The values are up to you... that is the entire point of generics.
If item is a type like List<T> then item.GetGenericArguments() will return an array containing a fake "type" representing the type parameter T (with its IsGenericParameter property set to true). Therefore, passing that parameter type back into item.MakeGenericType() will simply create another open generic type equivalent to the original. To close the generic type so that it can be instantiated you need to provide an actual (non-parameter) type argument, such as int.
For example, typeof(List<>).MakeGenericType(typeof(int)) will return typeof(List<int>), while typeof(List<>).MakeGenericType(typeof(List<>).GetGenericArguments()) will simply return typeof(List<>) again. This is what is happening in your code.
I'm sorry if that is a bit opaque, I don't know how else to explain it. The bottom line is that a type like List<T> is only useful if you have a type you want to substitute in place of T.

Related

Set type dynamically for method call

I have a static function:
public static MyCollection<T> Parse<T>(string? json) where T : BaseClass
{
...
}
And it works fine. It makes decisions internally based on the type and produces the correct collection.
But, the collection I want is based on a file name coming in from another source and I was hoping to have one collection and dynamically set the type, as in:
Type t;
if (name == "Certain name") t = typeof(CertainChildClassOfBaseClass);
if (name == "Other name") t = typeof(OtherChildClassOfBaseClass);
var myCollection = ParsingService.Parse<t>(jsonString);
This obviously doesn't work, but is what I'm trying possible? I don't really want to write a bunch of if/else blocks with nearly identical content just so each one can have a different type (I already wrote those type-specific blocks inside the Parse function - doing the same branching twice seems like maybe I've made a more fundamental mistake). I am open to suggestions on how to do this the "right" way. Maybe I have to do this with reflection, which doesn't thrill me, but isn't the end of the world. One possible issue is the my parsing service is static.
Help is always appreciated.
Usually, I would recommend making Parse non generic, and then have a generic overload:
public static MyCollection<BaseClass> Parse(Type type, string? json)
{
...
}
public static MyCollection<T> Parse<T>(string? json) where T : BaseClass
{
return (MyCollection<T>)Parse(typeof(T), json);
}
But you can't make MyCollection contravariant because it's a concrete class, so that cast is illegal. And anyway, contravariant containers are dangerous to use (just look at arrays, for example).
The other method is to use reflection to get the version of the method you want (a process known as "closing" the generic type):
var genericMethod = typeof(/* class containing Parse */).GetMethod("Parse");
var method = genericMethod.MakeGenericMethod(type); // type will be substituted for your 'T', above
object collection = method.Invoke(json); // call the method
And here we hit another snag: collection's type will be object, and you need to cast it to something else. But you can't use MyCollection<T> because you don't know T, and you can't use MyCollection<BaseClass> because, well, no contravariance, again.
So really the main blocker is that MyCollection type. As long as it is that way, you have no easy way to go around it. You could instead return a non generic collection, like ICollection or IList, but then you lose type safety and you'll have to keep casting more later. It's up to you, really.

Convert IEnumerable<A> to IEnumerable<B> without knowing types at compile time

I have two types: let's call them A and B. A can be converted to B using an adapter method.
I then have a collection of A's in a List<A> (it could be any collection type that supports IEnumerable<A>).
I now want to convert from IEnumerable<A> to IEnumerable<B>. I know the Type of each of A and B, and I have a method to convert an A into a B, but my method and/or class is not templated itself, so I do not have access to the template type; e.g. the T in IEnumerable<T>.
I effectively want to write this ConvertCollection method, where I know "from" is of type IEnumerable<{something}>:
object ConvertCollection(object from, Type fromType, Type toType, Converter converter);
My converter looks like this:
delegate object Converter(object from);
My attempt leaves me here:
object ConvertCollection(object from, Type fromType, Type toType, Converter converter)
{
return ((IEnumerable<object>)from).Select(converter);
}
which partly works. If I call it like this
ConvertCollection(new List<A>() { new A() }, typeof(A), typeof(B), AToBConverter);
the returned collection does contain a collection of Bs, but the collection itself is of type IEnumerable<object>, not IEnumerable<B>, because I don't know how to cast to IEnumerable<{toType}>. (It matters because the result needs to be serialized).
I can attack it from the other end and create the correct return type like this:
var result = Activator.CreateInstance(typeof(List<>).MakeGenericType(toType));
// TODO: populate result here
return result;
but then the problem is that to achieve the TODO part, I need to call List<> methods on result, but I can't cast it to any type of List<> because of Co/ContraVariance rules, so even though I know the type supports List<> methods, I can't get at them to use them to populate the list; e.g. to use Add().
Is there a way to do this without using 'dynamic' and without too much reflection? I know I could locate and invoke the Add() method via reflection, but it seems like it shouldn't be necessary.
.NET 4.0 BTW
-- Clarification
As Euphoric correctly speculates, and I tried but rather badly failed to convey above, I know the types A and B at runtime, but I do not know them at compile time. Hence the direct use of generics is not an option. I do know that the collections (both supplied and as must be returned) implement the generic IEnumerable<>. That is all fixed and outside my control. (I've adjusted the title accordingly).
** Edit 2: fixed some formatting causing <> to not display (easy to accidentally omit the back-ticks!)
Using the LINQ Select method:
var result = listA.Select(a => Converter(a));
Since you are using .NET 4.0, you really should avoid using object and use generics.
The solution I settled on was to use reflection to invoke the Enumerable.Cast<> method to cast the resultant collection from IEnumerable<object> to the correct IEnumerable<> type. I got the idea from the answer to this question: Convert IEnumerable to IEnumerable<T> when T isn't known until runtime. Seems to involve very little performance penalty.
So the full answer becomes:
object ConvertCollection(object from, Type fromType, Type toType, Converter converter)
{
var partialResult = ((IEnumerable<object>)from).Select(converter);
var castMethod = typeof(Enumerable).GetMethod("Cast").MakeGenericMethod(toType);
return castMethod.Invoke(null, new[] { partialResult });
}
Maybe something like this?
IEnumerable<TTo> ConvertCollection<TFrom,TTo>(object from, Converter converter)
{
return ((IEnumerable<TFrom>)from).Select(a=>(TTo)converter(a)).ToList();
}
Then you simply call it:
ConvertCollection<A,B>(new List<A>() { new A() }, AToBConverter);

Determining the expected type of a DynamicObject member access

Is it possible to determine what type a dynamic member access expects? I've tried
dynamic foo = new MyDynamicObject();
int x = foo.IntValue;
int y = (int)foo.IntValue;
And in the TryGetMember intercept GetMemberBinder.ReturnType is object either way. I also implemented TryConvert wondering if it might get invoked to do the conversion, but it never is hit.
Is there some other override I'm missing that lets me determine what Type the caller wants so that I can do the appropriate conversion?
In C#, when using dynamic, the compiler always sets the binder to return type of object, and then does a second dynamic implicit conversion to the expected return type. So on a DynamicObject when called from c#, GetMemberBinder.ReturnType will always be object, but that said if you return another sort of springboard dynamic object with TryConvert implemented you could get that type, except if the user does var or dynamic as the variable, then they have a proxy that won't do anything until it becomes statically typed.
ImpromptuInterface does something different but along these lines, because it also has the desire to have a dynamic implementation that changes based on return types -- just you would have to describe the dynamic object via an interface.

How to create an instance of value types using reflection

I want to create an instance of value types like System.String, System.Boolean, System.Int32, etc. I get qualified names of types like System.String or MyNamespace.Employee and I have to create an instance and return back. I use Activator.CreateInstance and FormatterServices.GetUninitializedObject to create instances. But it fails in case of value types. I cannot hard code the logic in case of value types. I need a generic way of creating instances of both value types and reference types.
What exactly is it you are trying to do? FormatterServices.GetUninitializedObject is used mainly by serialization code; outside of that you shouldn't really use it. It sounds like you might just need something like TypeConverter, i.e. (for these types)
TypeConverter tc = TypeDescriptor.GetConverter(someType);
object obj = tc.ConvertFromString(s);
What exactly is failing? I tried the following code to see if there is a problem with value types:
var instance = Activator.CreateInstance(typeof(Int32));
It gives me an Int32 instance set to 0.
Where exactly is your code failing? Otherwise I would say the problem lies with the way you are loading the type, not the way you are creating the instance.
For BCL Value Types (and when using Strings to describe types) ensure you are not using C# keywords and ensure the Type is fully qualified with namespace. For example, C# int is successfully created this way with Activator.CreateInstance(..)
object num = Activator.CreateInstance(Type.GetType("System.Int32"));
You will get failed attempts if you try to use language-specific aliases like "int" or short forms like "Int32".
This works for me:
int x = (int)Activator.CreateInstance(typeof (Int32), true);

Why this is not possible in C# Generics?

A colleague pointed me to a strange case in C# (not so sure if this actually strange though).
Suppose you have a class Employee. If you want to create a Generic List<> of type Employee, you can simply do:
List<Employee> x = new List<Employee>;
I understand that I need to pass the Employee type to the Generic list so that it knows the required type information about Employee and generates methods that return and accept parameters that are compatible with Employee.
Now my question is, why isn't it possible to do the following?
Employee x = new Employee();
List<typeof(x)> list = new List<typeof(x)>();
Shouldn't this suffice the information required for List<> to know, in order to create a list? In other words, the type of x which is the type of Employee is now passed as a generic type parameter to List<>, which (as I used to believe) is the same as passing list the type name (in this case Employee).
I know that something like this is available in Java (using the .class) keyword on a variable.
I'm sure I AM missing something, so please, enlight me guys!
No, the equivalent of that isn't available in Java. You can't use "x.class" to get at the declared type of a variable.
Moreover, typeof(x) doesn't work in C# either to get the type of a variable - it returns a Type reference for the type name, e.g. typeof(string) will return a reference to the Type object associated with the System.String type. That's equivalent to using String.class in Java. (Note that again, that's applying .class to a type name, not a variable name.)
Java generics don't support anything like your final statement either. If you believe they do, please give a sample :)
What you can do in C# is use type inference to do what you want:
public static List<T> CreateListForSampleType<T>(T sample)
{
return new List<T>();
}
...
Employee x = new Employee();
var list = CreateListForSampleType(x);
Note that there's no reason why C# couldn't be extended to allow something like typeof(variablename) or List<typeof(variablename)> - it's all compile-time type information, after all. However, I can't see that it would meet the team's requirements for usefulness... there are other far more useful features I'd like to see first :)
The reason for this is that typeof() returns a type object, while you need a type name to initialize a list at compile-time.
One part of the answer is that the type of x is not available at compile time, i.e. it might be created using something like this:
Employee x = EmployeeFactory.NewEmployee("John Doe"); // Returns TraineeEmployee, Employee or ManagementEmployee;
List<typeof(x)> l = new List<typeof(x)> l(); // What type is it?
You can however create a List of a base class of what you want to store in the list (or even a List of "object"s).
typeof is used with class names. Use GetType() on an object, but only at runtime...
What you are missing - imho - is the difference between a static type reference at compile-time and a dinamyc type reference (via an instance of System.Type) at run-time.
typeof() and .GetType() give you the latter. (for types and instances, respectively)
I hope it makes clear.
Jon Skeet's code above is cool.
Can't find a reason to create an empty list since C# 3.0.
I generally create list instances only with a ToList method from an IEnumerable, which is in turn generated using a yield return, Concat(), Repeat(), Where() etc.
var list = CreateEmployees().ToList();
,
public IEnumerable<Employee> CreateEmployees()
{
yield return new Employee("Foo");
yield return new Employee("Bar");
}

Categories