簡體   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