将接收到的对象转换为List<object>或IEnumerable<object>

86

我正在尝试执行以下类型转换:

private void MyMethod(object myObject)  
{  
    if(myObject is IEnumerable)  
    {
        List<object> collection = (List<object>)myObject;  
        ... do something   
    }  
    else  
    {  
        ... do something  
    }  
}

但我总是遇到以下异常:

无法将类型为 'System.Collections.Generic.List1[MySpecificType]' 的对象强制转换为类型为 'System.Collections.Generic.List1[System.Object]' 的对象。

我真的需要这个方法能够非常通用地接收未指定类型的单个对象和集合。这可行吗,还是有其他实现方式?

谢谢。

10个回答

99

C# 4将具有协变和逆变模板参数,但在那之前,您必须像这样使用非泛型:


C#4将具有协变和逆变模板参数,但在那之前,您必须使用类似于非泛型的东西。
IList collection = (IList)myObject;

1
@Sergio,如果你想避免运行时错误的风险,在强制转换之前应该检查myObject是否实现了IList而不是IEnumerable。许多内置集合实现了IEnumerable但没有实现IList(例如Dictionary<>,HashSet<>,Hashtable,Queue,Stack等)。 - LukeH
@Luke:如果它是一个List<T>(这是问题所暗示的),那么它将实现IList。 - erikkallen
1
@erikkallen,没错,但这是OP应该意识到的问题。避免这个问题只需要在给定的示例中将“if (myObject is IEnumerable)”更改为“if (myObject is IList)”。 - LukeH
1
甚至更简洁的方式(如果使用 IEnumerable),是 Items.As<IEnumerable>()?.Cast<object>() ?? Enumerable.Empty<object>(),它的意思是:如果列表实现了 IEnumerable 并且结果不为空,则将这个泛型对象列表作为一个对象列表获取;否则,只获取一个空的对象枚举。 - user1618054

90

您无法将IEnumerable<T>强制转换为List<T>。

但您可以使用LINQ来完成:

var result = ((IEnumerable)myObject).Cast<object>().ToList();

3
这也会创建一个新的列表,而不是将原始列表转换。 - Cameron MacFarland
2
我不得不使用(IEnumerable<object>)而不是仅仅使用(IEnumerable),但除此之外一切正常。我使用的是dotnetcore 3.0。 - kkuilla

14

这段代码对我有用。

List<Object> collection = new List<Object>((IEnumerable<Object>)myObject);

11

问题在于你试图向更丰富的对象上转换。你只需要将项目添加到新列表中:

if (myObject is IEnumerable)
{
   List<object> list = new List<object>();
   var enumerator = ((IEnumerable) myObject).GetEnumerator();
   while (enumerator.MoveNext())
   {
      list.Add(enumerator.Current);
   }
}

10

你是否需要比普通的 IEnumerable 提供更多信息?只需将其转换为该类型并使用 foreach 即可。在 Protocol Buffers 的某些部分中,我也面临着完全相同的情况,而我发现将其转换为 IEnumerable(或者转换为 IList 以像列表一样访问它)非常有效。


8

你能行吗?

List<object> collection = new List<object>((IEnumerable)myObject);

3

必须加入这场有趣的活动...

    private void TestBench()
    {
        // An object to test
        string[] stringEnumerable = new string[] { "Easy", "as", "Pi" };

        ObjectListFromUnknown(stringEnumerable);
    }

    private void ObjectListFromUnknown(object o)
    {
        if (typeof(IEnumerable<object>).IsAssignableFrom(o.GetType()))
        {
            List<object> listO = ((IEnumerable<object>)o).ToList();
            // Test it
            foreach (var v in listO)
            {
                Console.WriteLine(v);
            }
        }
    }

1

Nowadays it's like:

var collection = new List<object>(objectVar);

0

你也可以将对象转换为DTO列表。

首先对myObject进行序列化,然后将其反序列化为列表。

以下是代码:

List<MyDto> myList = JsonConvert.DeserializeObject<List<MyDto>>(JsonConvert.SerializeObject(myObject));

上述代码中使用了 Newtonsoft.Json


0
你需要使用as操作符进行类型转换,就像这样。
private void MyMethod(object myObject)  
{  
if(myObject is IEnumerable)  
{
    List<object> collection = myObject as(List<object>); 
    ... do something   
}  
else  
{  
    ... do something  
}  
}      

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接