具有generics返回类型但不是通用输入的方法。 这可能吗?

假设我们有一个NodeData类:

 public class NodeData { 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> listOutputs() { var fieldInfos = GetType().GetFields(); var list = new List<NodeData>(); foreach (var item in fieldInfos) { Type t = item.FieldType; string name = item.Name; if (t == typeof(NodeData)) { var output = new NodeData(name, default(T)); list.Add(output); } } return list; } } public class TestNode : Node { public NodeData data; public NodeData data2; public NodeData data3; public TestNode () { data = new NodeData("test", 111); data2 = new NodeData("test", 113); } } 

正如您所看到的,有一种方法可以在Node类中列出类型为T所有输出。所以我可以在运行时找到子类的输出字段:

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

但我需要知道如何使用此方法列出任何类型T的所有NodeOutput。在此示例中为intdouble 。 我是否需要添加具有此签名的方法public List<NodeData> listOutputs() // should return all properties data, data2, data3 。 有可能有这样的方法吗? 返回类型是通用的,但方法没有类型参数。

即使在你的编辑之后你还没有完全清楚你想要实现什么,但这是我的假设: – 你想要某种Node对象作为不同类型的NodeData元素的容器。 – 您希望能够从包含Node容器中存储的所有NodeData元素的Node对象返回一个列表,而不管NodeData对象的类型如何。

而不是从listOutputs方法返回List>对象,只返回List对象的非generics版本。 然后你不必在方法调用中处理T.

循环遍历非generics列表中的对象的逻辑然后可以检查类型以正确处理包含的NodeData对象。

重要提示:我提出的解决方案绝不是很好,但我认为它回答了这个问题。 在我看来,从所提出的代码中的OO观点来看,某些东西已经存在严重缺陷(例如使用reflection),并且更好的解决方案必须从改变底层数据结构开始。 但只有在我们有更多信息如何使用它时才能做到这一点,例如,哪种逻辑会消耗返回的列表。

您可以创建将用于返回通用数据的基本接口。

 public interface INodeData { string Name { get; } } public class NodeData : 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 listOutputs() { var fieldInfos = GetType().GetFields(); var list = new List(); 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 data; public NodeData data2; public NodeData data3; public TestNode() { data = new NodeData("test", 111); data2 = new NodeData("test", 113); } } private static void Main(string[] args) { TestNode node = new TestNode(); var list = node.listOutputs(); // this returns data } 

这可能是一个XY问题,因为您可能想重新考虑如何设计类,因为以这种方式使用reflection似乎并不正确。 但是提出你提出的问题,我会像这样解决它:

 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 : 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 listOutputs() 

返回列表后,您可以使用GetValue方法获取实际值,而无需转换为正确的generics类型,以便能够获取Value属性。

您也可以只返回List的返回类型,但是在您可以访问它的属性之前,您必须将该列表的每个成员强制转换为正确的generics类型。

您也可以避免使用那些讨厌的reflection代码,而不是拥有datadata1data2 ,您可以在Node类中执行此操作:

 public class Node { public List Data { get; protected set; } public Node() { Data = new List(); } } 

现在你甚至不需要你的listOutputs方法,因为你可以从节点获取列表(除非你真的想要一个副本,但这实现起来相当简单)。

而你TestNode将只是:

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