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

Pao*_*sco 10 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>();
            // 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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我的问题是要做这样的事情,我需要指定一个约束

class Base<T> where T : Base {
}
Run Code Online (Sandbox Code Playgroud)

有可能以某种方式指定这样的约束吗?

Meh*_*ari 22

这可能对你有用:

class Base<T> where T : Base<T>
Run Code Online (Sandbox Code Playgroud)

您不能限制T为开放的泛型类型.如果您需要限制TBase<whatever>,你需要构建这样的:

abstract class Base { }

class Base<T> : Base where T : Base { ... }
Run Code Online (Sandbox Code Playgroud)

  • 但是,`class X:Base <X> {}`然后`class Y:Base <X> {}`很遗憾是合法的,很难检查.不是一个友好的程序员会这样做,但仍然. (4认同)
  • 哇,这是合法的吗? (2认同)

ja7*_*a72 8

我使用以下内容创建不是链接列表,而是创建一个generecic链接树.它非常好用.

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; } }
}
Run Code Online (Sandbox Code Playgroud)

力学的示例用法(坐标系层次结构)

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 );
       }
    }
}
Run Code Online (Sandbox Code Playgroud)

诀窍是用null父对象初始化根对象.记住,你不能这样做Coord3() : base(this) { }.