I've created a generic function as below (just a s a proof) that will take a List<T> collection and reverse it, returning a new List<T> as its output.
public static List<T> ReverseList<T>(List<T> sourceList)
{
T[] outputArray = new T[sourceList.Count];
sourceList.CopyTo(outputArray);
return outputArray.Reverse().ToList();
}
The purpose of the proof is that I only know what T is at runtime. I am therefore using reflection to call the above method as follows:
List<int> myList = new List<int>() { 1, 2, 3, 4, 5 }; // As an example, but could be any type for T
MethodInfo myMethod = this.GetType().GetMethod("ReverseList");
MethodInfo resultMethod = myMethod.MakeGenericMethod(new Type[] { typeof(int) });
object result = resultMethod.Invoke(null, new object[] { myList });
There are two problems here:
In the second line, rather than supplying typeof(int), I would like suppliy somthign akin to myList.GetType().GetGenericArguments()[0].GetType() in order to make things more flexible because I do not know T until runtime. Doing this results in a runtime error when the Invoke runs as follows: "Object of type 'System.Collections.Generic.List'1[System.Int32]' cannot be converted to type 'System.Collections.Generic.List'1[System.RuntimeType]'."
The result of the Invoke() method returns an object. When debugging, I can see that the object is of type List, but attempting to use it tells me that I have an invalid cast. I assume that I need to use reflection to box the result in to the correct type (i.e. in this example, the equivalent of (result as List<int>).
Does anyone have any pointers that could help me resolve this? Apologies if this is not to clear, I can probably provide more detail if asked.
TIA
You've got one GetType() too many. Happens to everyone.
myList.GetType().GetGenericArguments()[0] IS a System.Type -- the one you're looking for.
myList.GetType().GetGenericArguments()[0].GetType() is a System.Type describing System.Type (well, actually the concrete subclass System.RuntimeType).
Also, your ReverseList function is serious overkill. It does an extra copy just to avoid calling List.Reverse. There's a better way to circumvent that:
public static List<T> ReverseList<T>(List<T> sourceList)
{
return Enumerable.Reverse(sourceList).ToList();
}
or
public static List<T> ReverseList<T>(List<T> sourceList)
{
var result = new List<T>(sourceList);
result.Reverse();
return result;
}
or
public static List<T> ReverseList<T>(List<T> sourceList)
{
var result = new List<T>();
result.Capacity = sourceList.Count;
int i = sourceList.Count;
while (i > 0)
result.Add(sourceList[--i]);
return result;
}
To access it as a List<T>, yes you'd need to find T using reflection (probably over the interfaces, for example typeof(IList<>), and use more reflection and MakeGenericMethod etc. In all honesty, it isn't worth it: you would do better to check for the non-generic IList:
var list = result as IList;
if (list != null)
{
// loop over list etc
}
Generics ad reflection are not good friends.
Note in 4.0 there are also some tricks you can do here with dynamic and generics.
The result of the Invoke() method
returns an object. When debugging, I
can see that the object is of type
List, but attempting to use it tells
me that I have an invalid cast. I
assume that I need to use reflection
to box the result in to the correct
type (i.e. in this example, the
equivalent of (result as List).
The only workaround for this is I can think of is to pass an empty list as the second parameter of the method and to populate that list - the reference returned by Invoke() will always be only of type object, but inside the generic method you do have access to the type itself:
List<int> reverseList = new List<int>();
resultMethod.Invoke(null, new object[] { myList, reverseList });
...
public static void ReverseList<T>(List<T> sourceList, List<T> resultList)
{
T[] outputArray = new T[sourceList.Count];
sourceList.CopyTo(outputArray);
resultList.AddRange(outputArray.Reverse());
}
Related
The method I am overriding has the following signature.
public override bool IsValid(object value)
The object that is passed in is a List but the the list type is unknown. It could be List<string> or List<int>.
I need to cast this into a List<object>. I've tried
if (!(value is IList temp))
{
return false;
}
List<object> list = temp.OfType<object>().ToList();
which sort of works, but it filters out any null values, presumably because they are not OfType<object>
So what's the best way of doing this?
temp.OfType().ToList();
OfType checks if the element is of the required type, and if so it puts it in a new temporary list.
What you're asking is simply a cast, since every instance in C# is an object: (List<object>)temp. Edit: apparently covariance doesn't work here.
There's absolutely no reason to do this though, you can simply enumerate it as it is: foreach(var obj in (IList)temp). All collections implement the IList non-generic interface.
If the input is either List<int> or List<string> and nothing else, then I think the best approach is to check specifically for these types. So something like:
List<object> list ;
if (value is List<int> listOfInts)
{
list = listOfInts.Cast<object>().ToList();
}
else if (value is List<string> listOfStrings)
{
list = listOfStrings.Cast<object>().ToList();
}
else
{
throw new ArgumentException(...);
}
This might seem redundant, but it might save you a lot of headache down the line, since you will catch if someone passes a List<SomethingElse> or even a List<object> which would be illegal according to your specification.
GIVEN:
If you have the values:
Type type
IEnumerable enumerable
And the following conditions are met:
typeof(IEnumerable).IsAssignableFrom(type)
enumerable.All(element => element.GetType() == type.GetElementType())
GENERAL QUESTION:
Is it possible to create an instance of type via reflection that contains all of the elements of enumerable?
BACKGROUND:
Most of the types in System.Collections have a constructor like Example(ICollection), and if type has a constructor like that it is simple and straightforward to do Activator.CreateInstance(type, enumerable). For types like Dictionary<TKey, TValue> though, it is not that simple. The only solution I have thought of looks like this:
var dictionary = (IDictionary) Activator.CreateInstance(type);
var elementType = enumerable.First().GetType();
var key = elementType.GetProperty("Key");
var value = elementType.GetProperty("Value");
foreach (var element in enumerable)
{
dictionary.Add(key.GetValue(element), value.GetValue(element));
}
I would be more willing to accept this solution of KeyValuePair<TKey, TValue>implemented an interface which contained the properties Key and Value so you could say:
var keyValuePair = (IKeyValuePair) element;
dictionary.Add(keyValuePair.Key, keyValuePair.Value);
rather than relying on reflection to get the aforementioned property values.
This solution would only work for types within System.Collections or custom types that strongly adhere to the definitions of said types.
SPECIFIC QUESTION:
Is there a more elegant way of converting enumerable to the type of typethat also could account for edge cases like MyCollection : ICollection, where the type definition is not known to us?
UPDATE:
Here is an example:
var original = new Dictionary<int, string>
{
//values
};
var type = original.GetType();
var enumerable = original.AsEnumerable();
var copy = (Dictionary<int, string>) DoSomeMagic(type, enumerable);
object DoSomeMagic(Type type, IEnumerable enumerable)
{
//Add magic here
}
This is one of the few reasons left to use good old ArrayList.
System.Array ConvertUnknownIEnumerableToArray(IEnumerable ienumerable, Type type)
{
var list = new ArrayList();
foreach (var i in ienumerable) list.Add(i);
return list.ToArray(type);
}
The above creates a strongly typed array (named array) of the concrete objects contained in any enumerable named ienumerable. An array, of course, implements ICollection.
This technique allows you to avoid Reflection figuring out which generic MethodInfo to create and invoke to create the array. The framework does it for you.
I have a C# method which uses object as a generic container to return a data array which could be declared using different data types. Below a simplified example of such a method:
void GetChannelData(string name, out object data)
{
// Depending on "name", the underlying type of
// "data" can be different: int[], byte[], float[]...
// Below I simply return int[] for the sake of example
int[] intArray = { 0, 1, 2, 3, 4, 5 };
data = intArray;
}
I need to convert all the returned array elements to double but so far I could not find a way. Ideally I would like to perform something like:
object objArray;
GetChannelData("test", out objArray);
double[] doubleArray = Array.ConvertAll<objArray.GetType().GetElementType(), double>(objArray, item => (double)item);
Which miserably fails because ConvertAll does not accept types defined at runtime. I have also tried intermediate conversions to a dynamic variable, to no avail.
Is there any way to perform such type conversion in a simple manner?
If you don't know the type at compile time you can try to convert it.
var array = (IEnumerable)objArray;
var doubles = array.OfType<object>().Select(a => Convert.ToDouble(a)).ToArray();
If you don't know the type of array elements at compile-time:
var doubleArray = (objArray as Array).OfType<object>()
.Select(m => Convert.ToDouble(m)).ToArray();
u can create extension method..
public static IEnumerable<T> Convert<T>(this IEnumerable source)
{
foreach (var item in source)
yield return (T)System.Convert.ChangeType(item, typeof(T));
}
using ..
object objArray;
GetChannelData("test", out objArray);
var array = (IEnumerable)objArray;
var doubleArray = array.Convert<double>().ToArray();
I'm using Value Injecters to map from 1 type to another using the LoopValueInjection and overriding the SetValue(object v) method with some custom logic. I am trying to detect when a HashSet is being passed in and go through the HashSet and apply a method to each item in it to do some clean up. The issues I'm having are because the parameter is just an object and I don't know what the type of item will be in the HashSet. For example, it could be HashSet or HashSet.
Here is the code I currently have but I'm getting an InvalidCastException.
protected override object SetValue(object v)
{
if (type.Name == "HashSet`1")
{
var genericType = type.GetGenericArguments()[0];
// this line throws the InvalidCastException
var cleanHashSet = (HashSet<object>)Activator.CreateInstance(type);
foreach (var item in (HashSet<object>)v) // I'm sure this cast will throw as well
{
cleanHashSet.Add(Clean(item));
}
return cleanHashSet;
}
return base.SetValue(v);
}
I guess the main question is how can I loop through the HashSet that is passed in as an object once I determine it is in fact a HashSet of some kind? I'm also thinking I will need to create a new empty HashSet of the specific type as well so I can put each item that gets cleaned up into it.
In .NET only interfaces and delegate types can be co- and contra-variant. So it is not possible to cast HashSet<SomeType> to HashSet<object>.
You want to cast your v to non-generic version of IEnumerable interface
dynamic cleanHashSet = Activator.CreateInstance(type);
foreach (object item in (IEnumerable)v)
{
cleanHashSet.Add(Clean(item));
}
If you don't want to use dynamic keyword then you need to call Add method with reflection
object cleanHashSet = Activator.CreateInstance(type);
var method = type.GetMethod("Add");
foreach (object item in (IEnumerable)v)
{
method.Invoke(cleanHashSet, new object[] { Clean(item) });
}
Use:
bool isHashSet = typeof(HashSet<object>).IsAssignableFrom(type);
or
object x = ...
HashSet<object> hs = x as HashSet<object>;
if (hs != null)
{
// use hs
}
If you really have <T> specified then use it instead of object.
HashSet<T> implements ICollection<T>, IEnumerabel<T>, IEnumerable. What means if you know T you can both enumerate and add. Otherwise enumerate only enumerate.
since yesterday i'm working on a problem and i don't get it yet...
I've got a class with many Methods and decide in Runtime wich Method has to be called. Every of this Methods returns a List with Elements from my Businessobjects.
My Class looks this way:
public class ReflectiveClass {
public List<BO1> DoSomethingWithBO1(int param){
List<BO1> list = new List<BO1>();
//....
return list;
}
public List<BO2> DoSomethingWithBO2(int param){
List<BO2> list = new List<BO2>();
//....
return list;
}
public void Process(){
//...get MethodInfo and so on
List<object> myReturnValue = (List<object>)methodInfo.Invoke(this, new object[]{param});
// here comes the Exception
}
}
So, at Invoking the Method i got a
InvalidCastException
and the Debugger told me he could not Cast from
System.Collections.Generic.List`1[BO1]
to
System.Collections.Generic.List`1[System.Object]
I wonder why this doesn't work. I thougt if i use a List every Object could be in this List.
I've even tried it with List but same behaviour.
Is it possible to read reflective the Type of the Return-Value of a Method? And can i then create a Generic List with this Returnvalue and cast to this List? This would be wonderfull.
Greetings and many Thanks for your Help!
Benni
Obviously BO1 derives from Object, and you can't cast List<Derived> to List<Base>. Suppose we have:
List<Apple> apples = AListOfApples();
List<Fruit> fruits = (List<Fruit>)apples; //suppose it's valid to cast
fruits.Add(new Orange()); //Of course we can add an Orange to the list of Fruit
//Now you can see the list of Apple has an Orange in it!!
You can use IEnumerable<T> instead.
If you have behaviour that changes and is determined at runtime, it's ideal for the Strategy pattern. Have a look at http://www.dofactory.com/Patterns/PatternStrategy.aspx
List<_> needs to be invariant to be statically type-safe. Imagine this compiled
var strlist = List<string> { "blub" };
var olist = (List<object>)strlist;
Up to this point everything is nice and dandy, but if you now tried to write to
the list like so
olist.Add(3);
the runtime would have to throw an exception as the underlying array is not an int array, but a string array. That's why it does not compile in the first place.
Note that contary to generic lists, arrays have been covariant since C# 1.0,
probably for Java compatibility. So this indeed compiles:
string[] strlist = new[] { "huhu" };
var olist = (object[])strlist;
olist[0] = 3;
... but throws an exception at runtime.
IEnumerable<out T> is covariant in T in C# 4.0 (therefore the out). Maybe this would be the more appropriate interface for your purposes.
You can use this :
object myReturnValue = mi.Invoke(this, new object[] { });
MethodInfo miToList = typeof(Enumerable).GetMethod("ToList");
MethodInfo miListObject = miToList.MakeGenericMethod(new[] { typeof(object) });
List<object> listObject = (List<object>)miListObject.Invoke(myReturnValue, new object [] { myReturnValue });
You should really split your class into two different classes, that should implement same interface. Using reflaction here is not a good thing.
Or if you methdods differ only in type of input parameters, make them generic.
Well the only solution is to create a new list..
public void Process(){
//...get MethodInfo and so on
List<object> myReturnValue = new List<object>(((IList)methodInfo.Invoke(this, new object[]{param})).ToArray());
// here comes no Exception!
}
I appreciate all the Answers!
For your information: I've implemented the Strategy Pattern, because it fits really good to my Project.
PS: I love this community, the peoble here help you so quick and with good solutions. Thanks!