繁体   English   中英

C# 在不知道“特定类型”是什么的情况下将多态 object 转换为特定类型

[英]C# cast polymorphic object into specific type without knowing what that 'specific type' is

提前致谢,社区!

正如标题所描述的,我想将父类型中的 object 转换为子类型,这实际上是子类型,而这个“特定类型”直到运行时才能知道。

可以说我有以下数据持有者:

public class Holder {}

public class Holder<T> : Holder
{
    public T Value;
}

而这个 Holder(不是 Holder<T>)会在运行时被交给某个脚本。

我需要将此 Holder 转换为 Holder<T>(例如,Holder<string>),以便我可以访问值:T。

现在,我可以手动添加转换案例及其相应的方法来处理它,但随着时间的推移,会有更多的类型进入这个 Holder<T>,这样就无法管理了。

有没有办法实现这个目标?

此 Holder 不得展平,因为它在以下上下文中使用:

public class SomeNode
{
    protected Holder holder;
}
public class SomeNode<T> : SomeNode
{
    public SomeNode<T>()
    {
        holder = new Holder<T>();
    }
}

我不知道如何处理这个问题,也不知道搜索关键字来获取有关此的提示。 在发布之前出现自动建议似乎不是我的情况,它们是:

C# 在运行时创建(或转换)特定类型的对象

C# 在不知道特定类型的情况下访问泛型方法

社区。 这是个好问题。 那很有趣。 我认为这很容易解决这个问题。 我们只需要创建一个像下面这样的简单构造函数


public class Holder
{
    public string SomeData;  // just example data

    public Holder()
    {
        
    }
    
    public Holder(Holder someData)
    {
        SomeData = someData.SomeData;
    }
}

public class Holder<T> : Holder
{
    public T Value;

    public Holder(Holder a, T t = default)
        :base(a)
    {
        Value = t;
    }
}

public class Programm
{
    void Main()
    {
        var h = new Holder();
        var g = new Holder<string>(h);
    }
    
}

如果您需要转换为特定类型,则多态性是错误的。 当然你可以这样做:

switch (holder)
{
    case Holder<string> stringHolder:
        DoStringThing(stringHolder.Value);
        break;
    case Holder<int> intHolder:
        DoIntThing(intHolder.Value);
        break;
    ...
}

另请参阅: 带模式的 Switch 语句

然而,多态性背后的思想是能够在不知道特定类型的情况下做事。 因此,重新设计 holder 类并让它们自己做特定类型的事情:

public abstract class Holder
{
    public abstract void DoThing();
}

public abstract class Holder<T> : Holder
{
    public abstract T Value { get; }
}

特定类型的一些示例:

public class StringHolder : Holder<string>
{
    public StringHolder(string value)
    {
        Value = value;
    }

    public override string Value { get; }

    public override void DoThing()
    {
        Console.WriteLine($"String of length {Value.Length} is \"{Value}\"");
    }
}

public class IntHolder : Holder<int>
{
    public IntHolder(int value)
    {
        Value = value;
    }

    public override int Value { get; }

    public override void DoThing()
    {
        Console.WriteLine($"The integer {Value} is {(Value % 2 == 0 ? "even", "odd")}");
    }
}

现在你可以简单地写

holder.DoThing();

...无需投射。

暂无
暂无

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

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