简体   繁体   中英

C# Cast List of MyType to List of objects

I'm writing an application where I am required to use Reflection to call a method which has parameters of type MyObject.

Method (List<MyObject> input , out List<MyObject> output,..... );

Using reflection I send the parameter of type Object. How can I cast List<MyObject> to List<object>

var parameters = new Object[] { inputs, outputs, userPrams };
System.Type classType = typeof(MyClass);
object instance = Activator.CreateInstance(classType);
classType.InvokeMember(name, BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public,null, instance, parameters);

In the code above both input and output are lists of type MyObject

I tried to Cast them to List of Objects but this doesn't work

x.Outputs = grOutputs as IList<object>

Can anyone help?

Your question is not 100% clear, so I assumed the problem you're facing is the one you put in the title:

Cast List of MyType to List of objects

As @Charles said, IList<T> and List<T> are not variant, so you can't cast IList<DerivedClass> to IList<BaseClass> . You have to create new List<BaseClass> .

There are many ways to do that, I think there are two you should consider:

  1. You can use Cast and ToList , but it will require using System.Linq .

     var listOfStrings = new List<string>() { "foo", "bar" }; var listOfObjects = listOfStrings.Cast<object>().ToList(); 
  2. To avoid that, you can use new List<T>(IEnumerable<T> source) constructor. Because IEnumerable<T> is covariant, you can do following:

     var listOfStrings = new List<string>() { "foo", "bar" }; var listOfObjects = new List<object>(listOfString); 

You might well want to do something like this:

var dogs = new List<Dog>();
var pets = (List<object>)dogs;
pets.Add(new Cat());

The C# language is heavily invested in you stop mixing cats and dogs like this. It violates the hard guarantee that the list only ever contains dogs. You'll have to do it like this instead:

var dogs = new List<Dog>();
var pets = new List<object>(dogs);
pets.Add(new Cat());

Which is fine, it creates a new list, one that no longer guarantees that it only ever contains dogs since it only promises that the list contains object . Pretty useless, typically, you basically lose all knowledge of what the list contains. Forcing you to write hunt-the-fox code that uses the as operator or Reflection to find the proper animal back. Code that fails to do its job at run-time instead of the compiler telling you that its wrong code at build time, when you're still in the comfortable cubicle cocoon.

Which it did.

IList<T>不是协变的,如果你想要IList<object> ,你需要创建一个新的列表:

x.Outputs = grOutputs.Cast<object>().ToList();

You cannot make your desired cast because, as others have written, collections in c# are not covariant .

You can either create a new list, or introduce a ListWrapper class like so:

public class ListWrapper<TOut, TIn> : IList<TOut> where TIn : class, TOut where TOut : class 
{
    readonly IList<TIn> list;

    public ListWrapper(IList<TIn> list)
    {
        if (list == null)
            throw new NullReferenceException();
        this.list = list;
    }

    #region IList<TOut> Members

    public int IndexOf(TOut item)
    {
        TIn itemIn = item as TIn;
        if (itemIn != item)
            return -1;
        return list.IndexOf(itemIn);
    }

    public void Insert(int index, TOut item)
    {
        list.Insert(index, (TIn)item);
    }

    public void RemoveAt(int index)
    {
        list.RemoveAt(index);
    }

    public TOut this[int index]
    {
        get
        {
            return list[index];
        }
        set
        {
            list[index] = (TIn)value;
        }
    }

    #endregion

    #region ICollection<TOut> Members

    public void Add(TOut item)
    {
        list.Add((TIn)item);
    }

    public void Clear()
    {
        list.Clear();
    }

    public bool Contains(TOut item)
    {
        TIn itemIn = item as TIn;
        if (itemIn != item)
            return false;
        return list.Contains(itemIn);
    }

    public void CopyTo(TOut[] array, int arrayIndex)
    {
        foreach (var item in list)
        {
            array[arrayIndex] = item;
            arrayIndex++;
        }
    }

    public int Count
    {
        get { return list.Count; }
    }

    public bool IsReadOnly
    {
        get
        {
            return list.IsReadOnly;
        }
    }

    public bool Remove(TOut item)
    {
        return list.Remove(item as TIn);
    }

    #endregion

    #region IEnumerable<TOut> Members

    public IEnumerator<TOut> GetEnumerator()
    {
        foreach (var item in list)
            yield return item;
    }

    #endregion

    #region IEnumerable Members

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    #endregion
}

You might want to make the wrapper read-only since the setter could throw an exception if the incoming object is not of the inner list's item type.

如果我理解你的问题,你可以尝试这样的事情:

var objList = myClassList.OfType<object>();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM