简体   繁体   English

C#将MyType的列表转换为对象列表

[英]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. 我正在编写一个应用程序,我需要使用Reflection来调用一个具有MyObject类型参数的方法。

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

Using reflection I send the parameter of type Object. 使用反射我发送Object类型的参数。 How can I cast List<MyObject> to List<object> 如何将List<MyObject>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 在上面的代码中,输入和输出都是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: 你的问题不是100%明确,所以我认为你面临的问题是你在标题中提出的问题:

Cast List of MyType to List of objects 将MyType的列表转换为对象列表

As @Charles said, IList<T> and List<T> are not variant, so you can't cast IList<DerivedClass> to IList<BaseClass> . 正如@Charles所说, IList<T>List<T>不是变体,因此您无法将IList<DerivedClass>IList<BaseClass> You have to create new List<BaseClass> . 您必须创建新的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 . 您可以使用CastToList ,但需要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. 为避免这种情况,您可以使用new List<T>(IEnumerable<T> source)构造函数。 Because IEnumerable<T> is covariant, you can do following: 因为IEnumerable<T>是协变的,所以你可以这样做:

     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. C#语言投入大量资金用于停止像这样的猫狗混合。 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. 强迫你编写使用as运算符或Reflection的hunt-the-fox代码来找回适当的动物。 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 . 您无法进行所需的演员表,因为正如其他人所写,c#中的集合不是协变的

You can either create a new list, or introduce a ListWrapper class like so: 您可以创建新列表,也可以像这样引入ListWrapper类:

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. 您可能希望将包装器设置为只读,因为如果传入的对象不是内部列表的项类型,则setter可能会抛出异常。

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

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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