如何在 C# 中将列表或数组转换为子类型?

Posted

技术标签:

【中文标题】如何在 C# 中将列表或数组转换为子类型?【英文标题】:How to cast a list or array to a subtype in C#? 【发布时间】:2021-06-22 03:13:37 【问题描述】:

我有一个包含对象列表成员的类。假设我有一个 Animal 基类和 Cat 和 Dog 的子类型。该列表将始终只包含 Dogs 或 Cats,但我事先并不知道。

class MyClass 

    public readonly List<Animal> Data = new();

    public void MethodForDogs()
    
        Data.Add(new Dog());
    

    public void MethodForCats()
    
        Data.Add(new Cat());
    

    public void DoSomething()
    
        HelperClass.DoIt(Data);
    


class HelperClass 

    public static void DoIt(List<Animals> data) 

        if (data[0].GetType() == typeof(Cat) ) 
            var arrayCats = new Cat[data.Count];
            int i = 0;
            foreach (Animal item in data) 
                arrayCats[i++] = (Cat) item;
            
            // use arrayCats
            ..
        
        else if (data[0].GetType() == typeof(Dog) 
           // same, then use arrayDogs
           ..
        
    

什么不起作用的是直接演员,比如

var arrayCats = (Cat[])data.ToArray();

即使我可以检查所有成员都是猫。有没有更优雅的方法来做到这一点?

【问题讨论】:

***.com/questions/1297231/… - 这会有帮助吗? 这能回答你的问题吗? convert a list of objects from one type to another using lambda expression 如果你确定你的数组只包含猫,var output = data.Cast&lt;Cat&gt;()。如果你只是想带猫出去,var output = data.OfType&lt;Cat&gt;() @MarkusE 这是一个稍微不同的问题,因为这个问题是关于将字符串解析为整数,而这个问题只是一个普通的引用转换。 Sinatr,好问题,但所有的答案都有点垃圾。最接近的,使用Cast&lt;T&gt;(),使用new List&lt;T&gt;(x.Cast&lt;T&gt;())而不是x.Cast&lt;T&gt;().ToList(),并隐藏在噪音中 The list will always contain only Dogs or only Cats but i do not know up front.。如果你不得不这么说,那么你对多态性的使用本质上是错误的。如果它始终是T : AT : B 的可枚举列表,您可能应该在某处使用generics,或者重组您在某处使用多态性的方式。 【参考方案1】:

你可以这样做:

class HelperClass

    public static void DoIt(List<Animals> data)
    
         if(data.All(a => a is Dog))
         
              Dog[] dogs = data.OfType<Dog>().ToArray();
              // do something with dogs
         
         else if(data.All(a => a is Cat))
         
              Cat[] cats= data.OfType<Cat>().ToArray();
              // do something with cats
         
         else
         
            throw new ArgumentException("data must contain items of the same type");
         
     

使用All,您可以检查列表中的所有项目是否满足条件(在您的情况下为类型)。 OfType() 为您获取所有具有某种类型的项目(在您的情况下:所有项目)自动转换为该类型。如果列表是混合类型,该方法将抛出异常(当然,您可以使用更适合您需要的其他错误处理)。

但您也应该考虑@AlphaDelta 的评论。对我来说,这个列表只包含一个子类型似乎有点奇怪。

【讨论】:

感谢所有 cmets 和这个详细的答案,这就是我想要的。用例是最后我想为外部接口构建一个 JSON 对象,该对象本身设计得很糟糕,因为它根据上下文接受同名的不同数据类型。所以我可以选择以一种不太好的方式将它映射到有一些重复的对象(我做了),或者我可以做很好的多态性,然后在我尝试将我的对象转换为外来 JSON 时做一些额外的 Json 争吵。但该代码对我来说更难维护。

以上是关于如何在 C# 中将列表或数组转换为子类型?的主要内容,如果未能解决你的问题,请参考以下文章

在 C# 中将匿名类型转换为键/值数组?

如何在 C# 中将字节 [] 转换为日期时间?

如何在 C# 中将嵌套列表转换为 XML

如何在c#中将对象转换为数组? [关闭]

如何在 C# 中将结构转换为字节数组?

python - 如何首先根据初始列表的单个元素将列表拆分为子列表,然后在python中将列表的连续部分拆分为子列表?