具有相同泛型类类型泛型参数的类



我有一个表示前缀搜索树的类:

public class PrefixTree<TData>
{
private PrefixTree<TData>[] _children;
private void SomeMethod()
{
_children = new PrefixTree<TData>[10];
}
}

然后我创建了一个派生类,为它的节点添加了额外的特性:

public class NewPrefixTree<TData> : PrefixTree<TData>

问题是,在SomeMethod()的派生类,我们仍然创建基类的实例,它不适合的意义。

我将基类重构为:

public abstract class PrefixTree<TData, TNode>
where TNode : PrefixTree<TData, TNode>, new()
{
private TNode[] _children;
private void SomeMethod()
{
_children = new TNode[10];
} 
}

尽管基类本身具有完整的功能,但我不得不将其命名为abstract,因为我不能写new DigitalPrefixTree<TData, DigitalPrefixTree<int,...>>().

但是现在我可以这样使用它,而且效果很好:

public class NewPrefixTree<TData> : PrefixTree<TData, NewPrefixTree<TData>> {} // for derived class
//or
public class PrefixTree<TData> : PrefixTree<TData, PrefixTree<TData>> {} // to use the base functionality

我以前从未这样做过,我想知道声明一个具有相同泛型类类型的泛型参数的类是否是个好主意。或者我需要用泛型接口的co/contro -variance做一些技巧(但它可能不起作用,因为我使用类类型作为方法的参数类型和返回类型)?

试试这个:

public interface INode<out TData>
{
TData Data { get; }
IEnumerable<INode<TData>> Children { get; }
public IEnumerable<TRequiredData> GetNestedData<TRequiredData>();
}
public interface ITree<out TData>
{
IEnumerable<INode<TData>> Children { get; }
IEnumerable<TRequiredData> GetNestedData<TRequiredData>();
}
public class Node<TData> : INode<TData>
{
public TData Data { get; }
public IEnumerable<INode<TData>> Children { get; }
public Node(TData data, IEnumerable<INode<TData>>? children = null)
{
Data = data;
Children = children ?? Enumerable.Empty<INode<TData>>();
}
public IEnumerable<TRequiredData> GetNestedData<TRequiredData>()
{
List<TRequiredData> result = new();
if (Data is TRequiredData requiredData)
result.Add(requiredData);
foreach (var child in Children)
result.AddRange(child.GetNestedData<TRequiredData>());
return result;
}
}
public class Tree<TData> : ITree<TData>
{
public IEnumerable<INode<TData>> Children { get; }
public Tree(IEnumerable<INode<TData>> children)
{
Children = children;
}
public IEnumerable<TRequiredData> GetNestedData<TRequiredData>()
{
List<TRequiredData> result = new();
foreach (var node in Children)
result.AddRange(node.GetNestedData<TRequiredData>());
return result;
}
}

下面是用法的例子:

record SomeRecord();
class SomeClass {}
static void Main(string[] args)
{
var nodeWithNested = new Node<SomeClass>(
data: new SomeClass(),
children: new List<INode<SomeClass>>()
{
new Node<SomeClass>(new SomeClass()),
new Node<SomeClass>(new SomeClass())
});
var nodes = new List<INode<object>>()
{
new Node<SomeClass>(new SomeClass()),
nodeWithNested,
new Node<SomeRecord>(new SomeRecord()),
};
var tree = new Tree<object>(nodes);
var someClasses = tree.GetNestedData<SomeClass>(); // 4 items
var someRecords = tree.GetNestedData<SomeRecord>(); // 1 item
}

这种方法基于我们的泛型修饰符。

唯一的限制是你不能使用结构体(int, bool等),因为它们没有共同的对象来强制转换。

希望对大家有帮助。

最新更新