简体   繁体   English

C# 存放不同的子类同时调用

[英]C# store different child classes and call them at same time

Actually all these classes are defined in the 3rd lib, so I can't change them.实际上所有这些类都在第三个库中定义,所以我无法更改它们。

===================== =====================

I'm learning C# and I met a problem.我在学习C#,遇到了一个问题。 Suppose I have a parent class and two child classes:假设我有一个父类 class 和两个子类:

class ParentClass
{
    ....
};

class ChildA : ParentClass
{
    public string name;
};

class ChildB : ParentClass
{
    public string name;
};

Both class ChildA and ChildB have property name , but ParentClass doesn't. class ChildA 和 ChildB 都有属性name ,但 ParentClass 没有。 Now I need to store ChildA and ChildB in a dictionary, so I write Dictionary<string, ParentClass> .现在我需要将 ChildA 和 ChildB 存储在字典中,所以我写了Dictionary<string, ParentClass>

But I can't get name because ParentClass doesn't have this property:但我无法获取名称,因为 ParentClass 没有此属性:

foreach (ParentClass pc in dict.Values) 
{
    // it works, but too verbose as I may have ChildC, ChildD...
    if (pc is ChildA ca) 
    {
        ca.name
    }
    if (pc is ChildB cb) 
    {
        cb.name
    }

    // how can I get the name property at same time?
}

how can I handle this?我该如何处理?

The short version is "no".简短的版本是“否”。 There are things that you could do if you have access to the types - for example, you could implement a common interface ( interface IHazName { public string Name {get;} } ) - but you can't do that here since you don't control the types.如果您有权访问这些类型,您可以做一些事情 - 例如,您可以实现一个通用接口( interface IHazName { public string Name {get;} } ) - 但你不能在这里这样做,因为你没有控制类型。

A lazy way could be to abuse dynamic :一种懒惰的方法可能是滥用dynamic

dynamic hack = pc;
hack.name = "yolo";

but... please don't!但是……请不要! Your is approach (or perhaps a switch expression) is about as good as you can get.is方法(或者可能是switch表达式)与您所能获得的一样好。 Note that if you need to talk to this member in a lot of places, you could move that shared logic to an extension method:请注意,如果您需要在很多地方与该成员交谈,您可以将该共享逻辑移至扩展方法:

static class SomeUtilsType {
    public static string GetName(this ParentClass obj) => obj switch {
        ChildA ca => ca.name,
        ChildB cb => cb.name,
        _ => throw new ArgumentException("Unexpected object type", nameof(obj)),
    };
}
...
foreach (ParentClass pc in dict.Values) 
{
    Console.WriteLine(pc.GetName());
}

(or a similar set method) - then at least you don't need to repeat yourself. (或类似的设置方法)——那么至少你不需要重复自己。

One way to do this is to use reflection on the type to determine if it has a "name" property (or field, as you've shown):一种方法是对类型使用反射来确定它是否具有“名称”属性(或字段,如您所示):

public static string GetName(ParentClass parent)
{
    return parent.GetType().GetProperty("name")?.GetValue(parent, null).ToString()
        ?? parent.GetType().GetField("name")?.GetValue(parent).ToString();
}

Example usage:用法示例:

static void Main(string[] args)
{
    ParentClass parent = new ParentClass();
    ChildA child = new ChildA { name = "ChildName" };

    Console.WriteLine($"Parent name: {GetName(parent)}");
    Console.WriteLine($"Child name: {GetName(child)}");

    Console.Write("\n\nDone. Press any key to exit...");
    Console.ReadKey();
}

Output Output

Parent name:
Child name: ChildName


Done. Press any key to exit...

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

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