簡體   English   中英

具有泛型返回類型但不是通用輸入的方法。 這可能嗎?

[英]Method with generic return type but not generic input. Is this possible?

假設我們有一個NodeData類:

public class NodeData<T>
{
    public string Name;
    public T Value;
    public NodeData(string name, T value)
    {
        this.Name = name;
        this.Value = value;
    }
}

以及具有NodaData類型的多個屬性的基類Node類和子類:

public class Node
{
    public List<NodeData<T>> listOutputs<T>()
    {
        var fieldInfos = GetType().GetFields();
        var list = new List<NodeData<T>>();
        foreach (var item in fieldInfos)
        {
            Type t = item.FieldType;
            string name = item.Name;
            if (t == typeof(NodeData<T>))
            {
                var output = new NodeData<T>(name, default(T));
                list.Add(output);
            }
        }
        return list;
    }
}

public class TestNode : Node {
    public NodeData<int> data;
    public NodeData<double> data2;
    public NodeData<double> data3;
    public TestNode ()
    {
        data = new NodeData<int>("test", 111);
        data2 = new NodeData<double>("test", 113);
    }
}

正如您所看到的,有一種方法可以在Node類中列出類型為T所有輸出。所以我可以在運行時找到子類的輸出字段:

TestNode node = new TestNode ();
var list = node.listOutputs<int>(); // this returns data

但我需要知道如何使用此方法列出任何類型T的所有NodeOutput。在此示例中為intdouble 我是否需要添加具有此簽名public List<NodeData<T>> listOutputs() // should return all properties data, data2, data3的方法public List<NodeData<T>> listOutputs() // should return all properties data, data2, data3 有可能有這樣的方法嗎? 返回類型是通用的,但方法沒有類型參數。

即使在你的編輯之后,你還沒有完全清楚你想要實現什么,但這是我的假設: - 你想要某種Node對象作為不同類型的NodeData元素的容器。 - 您希望能夠從包含Node容器中存儲的所有NodeData元素的Node對象返回一個列表,而不管NodeData對象的類型如何。

而不是從listOutputs方法返回List>對象,只返回List對象的非泛型版本。 然后你不必在方法調用中處理T.

循環遍歷非泛型列表中的對象的邏輯然后可以檢查類型以正確處理包含的NodeData對象。

重要提示:我提出的解決方案絕不是很好,但我認為它回答了這個問題。 在我看來,在所提出的代碼中從OO的角度來看已經存在嚴重缺陷(例如使用反射),並且更好的解決方案必須從改變底層數據結構開始。 但是,只有在我們有更多信息如何使用它時才能做到這一點,例如,哪種邏輯會消耗返回的列表。

您可以創建將用於返回通用數據的基本接口。

public interface INodeData
{
    string Name { get; }
}
public class NodeData<T> : INodeData
{
    public string Name { get; private set; }
    public T Value { get; private set; }

    public NodeData(string name, T value)
    {
        this.Name = name;
        this.Value = value;
    }
}

我修改了函數以返回接口列表。 這樣做你不會依賴於T

public class Node
{
    public List<INodeData> listOutputs()
    {
        var fieldInfos = GetType().GetFields();
        var list = new List<INodeData>();
        foreach (var item in fieldInfos)
        {
            INodeData data = GetType().GetField(item.Name).GetValue(this) as INodeData;
            list.Add(data);    
        }
        return list;
    }
}

如果您測試該方法,它應該返回列表中的字段。 要使用特定類型,您可以在使用搜索類型之前使用is

public class TestNode : Node
{
    public NodeData<int> data;
    public NodeData<double> data2;
    public NodeData<double> data3;

    public TestNode()
    {
        data = new NodeData<int>("test", 111);
        data2 = new NodeData<double>("test", 113);
    }
}

private static void Main(string[] args)
{
    TestNode node = new TestNode();
    var list = node.listOutputs(); // this returns data
}

這可能是一個XY問題,因為您可能想重新考慮如何設計類,因為以這種方式使用反射似乎並不正確。 但是提出你提出的問題,我會像這樣解決它:

public abstract class NodeDataBase
{
    public string Name { get; set; }

    public NodeData(string name)
    {
        this.Name = name;
    }

    // this isn't actually needed, but might be helpful
    public abstract object GetValue();

}


public class NodeData<T> : NodeDataBase
{
    public T Value { get; set; }
    public NodeData(string name, T value) : base(name)
    {
        this.Value = value;
    }

    public override object GetValue()
    {
        return Value;
    }
}

現在您的方法簽名將是:

public List<NodeDataBase> listOutputs()

返回列表后,您可以使用GetValue方法獲取實際值,而無需轉換為正確的泛型類型,以便能夠獲取Value屬性。

您也可以只返回List<object>的返回類型,但是在訪問它的屬性之前,您必須將該列表的每個成員強制轉換為正確的泛型類型。

您也可以避免使用那些討厭的反射代碼,而不是擁有datadata1data2 ,您可以在Node類中執行此操作:

public class Node
{
    public List<NodeDataBase> Data { get; protected set; }

    public Node()
    {
        Data = new List<NodeDataBase>();
    }
}

現在你甚至不需要你的listOutputs方法,因為你可以從節點獲取列表(除非你真的想要一個副本,但這實現起來相當簡單)。

而你TestNode將只是:

public class TestNode : Node {
    public TestNode ()
    {
        Data.Add(new NodeData<int>("test", 111));
        Data.Add(new NodeData<double>("test", 113));
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM