奇怪地重复出现的模板模式和泛型约束(C#)

奇怪地重复出现的模板模式和泛型约束(C#),c#,generics,constraints,C#,Generics,Constraints,我想在基本泛型类中创建一个方法,以返回派生对象的专门集合并对其执行一些操作,如以下示例所示: using System; using System.Collections.Generic; namespace test { class Base<T> { public static List<T> DoSomething() { List<T> objects = new List<T>();

我想在基本泛型类中创建一个方法,以返回派生对象的专门集合并对其执行一些操作,如以下示例所示:

using System;
using System.Collections.Generic;

namespace test {

    class Base<T> {

        public static List<T> DoSomething() {
            List<T> objects = new List<T>();
            // fill the list somehow...
            foreach (T t in objects) {
                if (t.DoSomeTest()) { // error !!!
                    // ...
                }
            }
            return objects;
        }

        public virtual bool DoSomeTest() {
            return true;
        }

    }

    class Derived : Base<Derived> {
        public override bool DoSomeTest() {
            // return a random bool value
            return (0 == new Random().Next() % 2);
        }
    }

    class Program {
        static void Main(string[] args) {
            List<Derived> list = Derived.DoSomething();
        }
    }
}
使用系统;
使用System.Collections.Generic;
名称空间测试{
阶级基础{
公共静态列表DoSomething(){
列表对象=新列表();
//以某种方式填写清单。。。
foreach(对象中的T){
如果(t.DoSomeTest()){//错误!!!
// ...
}
}
归还物品;
}
公共虚拟bool DoSomeTest(){
返回true;
}
}
派生类:基{
公共覆盖布尔剂量计测试(){
//返回一个随机布尔值
返回(0==new Random().Next()%2);
}
}
班级计划{
静态void Main(字符串[]参数){
List=派生的.DoSomething();
}
}
}
我的问题是要做这样的事情,我需要指定一个约束,比如

class Base<T> where T : Base {
}
类基,其中T:Base{
}

是否可以以某种方式指定这样的约束?

这可能适合您:

class Base<T> where T : Base<T>

我使用以下方法创建的不是链表,而是通用链接树。它工作得非常好

public class Tree<T> where T : Tree<T>
{
    T parent;
    List<T> children;

    public Tree(T parent)
    {
        this.parent = parent;
        this.children = new List<T>();
        if( parent!=null ) { parent.children.Add(this as T); }
    }
    public bool IsRoot { get { return parent == null; } }
    public bool IsLeaf { get { return children.Count == 0; } }
}
公共类树,其中T:Tree
{
T亲本;
列出儿童名单;
公共树(T父级)
{
this.parent=parent;
this.children=新列表();
如果(parent!=null){parent.children.Add(作为T);}
}
public bool IsRoot{get{return parent==null;}}
public bool IsLeaf{get{return children.Count==0;}
}
力学(坐标系层次)中的示例用法

类坐标3:树
{
矢量3位置;
矩阵3旋转;
private Coord3():this(Vector3.Zero,Matrix3.Identity){}
专用坐标3(矢量3位置,矩阵3旋转):基准(空)
{  
这个位置=位置;
这个旋转=旋转;
}
公共坐标3(坐标3父坐标、向量3位置、矩阵3旋转)
:基(父)
{
这个位置=位置;
这个旋转=旋转;
}
public static readonly Coord3 World=new Coord3();
公共坐标3 ToGlobalCoordination()
{
if(IsRoot)
{ 
归还这个;
}否则{
Coord3 base_cs=parent.toglobalcoord();
矢量3全局位置=
基础位置+基础旋转*此位置;
Matrix3全局旋转=基本旋转*this.rotation;
返回新坐标3(全局坐标、全局坐标);
}
}
}

诀窍是用
null
parent初始化根对象。请记住,您不能执行
Coord3():base(this){}

但是,
classx:base{}
然后
classy:base{}
不幸是合法的,很难检查。并不是说一个友好的程序员会这样做,但仍然如此。@Eamon:不幸的是,我们在ML类型的语言中没有类似于
unit
type的东西。我们刚刚创建了这个uservoice建议来为类似这样的代码添加更好的语言支持,请随意投票!
public class Tree<T> where T : Tree<T>
{
    T parent;
    List<T> children;

    public Tree(T parent)
    {
        this.parent = parent;
        this.children = new List<T>();
        if( parent!=null ) { parent.children.Add(this as T); }
    }
    public bool IsRoot { get { return parent == null; } }
    public bool IsLeaf { get { return children.Count == 0; } }
}
class Coord3 : Tree<Coord3>
{
    Vector3 position;
    Matrix3 rotation;
    private Coord3() : this(Vector3.Zero, Matrix3.Identity) { }
    private Coord3(Vector3 position, Matrix3 rotation) : base(null) 
    {  
       this.position = position;
       this.rotation = rotation;
    }
    public Coord3(Coord3 parent, Vector3 position, Matrix3 rotation) 
       : base(parent)
    {
       this.position = position;
       this.rotation = rotation;
    }
    public static readonly Coord3 World = new Coord3();

    public Coord3 ToGlobalCoordinate()
    {
       if( IsRoot )
       { 
            return this;
       } else {
            Coord3 base_cs = parent.ToGlobalCoordinate();
            Vector3 global_pos = 
                      base_cs.position + base_cs.rotation * this.position;
            Matrix3 global_rot = base_cs.rotation * this.rotation;
            return new Coord3(global_pos, global_ori );
       }
    }
}