强制子类将自身作为Generic参数传递给基类

时间:2015-01-07 04:51:00

标签: c# generics

我想强制我的子类将自己作为泛型参数传递给父类。

例如:

class BaseClass<T> where T: BaseClass
{
    //FullClassName : Tuple [Save,Update,Delete]
    Dictionary<string,Tuple<delegate,delegate,delegate>> dict = new Dictionary...;
    static BaseClass()
    {
        RegisterType();
    }

    private static void RegisterType()
    {
        Type t  = typeof(T);
        var props = t.GetProperties().Where(/* Read all properties with the SomeCustomAttribute */);
        /* Create the delegates using expression trees and add the final tuple to the dictionary */
    }

    public virtual void Save()
    {
        delegate d = dict[t.GetType().FullName];
        d.Item1(this);
    }
}

class ChildClass : BaseClass<ChildClass>
{
    [SomeCustomAttribute]
    public int SomeID {get;set;}

    [SomeCustomAttribute]
    public string SomeName {get; set;}
}

public class Program
{
    public static void Main(string[] args)
    {
        ChildClass c = new ChildClass();
        c.Save();
    }
}

显然上面的代码不会编译。我将重述:我希望子类将自己作为泛型参数传递,而不是BaseClass的任何其他子项。

(上面的代码是一种伪代码,仍然无法编译)。

3 个答案:

答案 0 :(得分:2)

你可以这样做:

public class BaseClass<T> where T: BaseClass<T> { }

public class ChildClass : BaseClass<ChildClass> { }

但是,这并不强迫使用ChildClass作为通用参数。你可以这样做public class OtherChildClass : BaseClass<ChildClass> { }这会破坏&#34; coontract&#34;你想强制执行。

答案 1 :(得分:1)

直接的答案是,如果您访问静态方法,那么typeof(T)将为您提供反射类型。

然而,可能有比使用反射更好的解决方案。选项:

1)子类的静态构造函数。

2)在基类中声明的抽象方法。

我不知道应用程序,但如果我想使用静态构造函数,我会担心我的设计,如果基类需要初始化子类,我也会担心。

我建议将注射视为解决方案而不是继承。它提供卓越的单元测试,通常还有更好的架构。

更多信息(在首发后),这是我首选的解决方案:

public interface IRegesterable
{
    void Register();
}

public class Widget : IRegesterable
{
    public void Register()
    {
        // do stuff
    }
}

public class Class1
{
    public Class1(IRegesterable widget)
    {
        widget.Register();
    }
}

希望这有帮助

答案 2 :(得分:1)

ConcurrentDictionary被用作Set<Type>。如果类型已初始化,我们可以检查Set<Type>。如果不是,我们就在类型上运行RegisterType

public abstract class BaseClass
{
    //Concurrent Set does not exist.
    private static ConcurrentDictionary<Type, bool> _registeredTypes 
            = new ConcurrentDictionary<Type, bool>();

    protected BaseClass()
    {
        _registeredTypes.GetOrAdd(GetType(), RegisterType);
    }

    private static bool RegisterType(Type type)
    {
        //some code that will perform one time processing using reflections

        //dummy return value
        return true;
    }
}

public class ChildClass : BaseClass
{
}

但这种模式存在一些效率低下的问题。

  • object.GetType()非常慢,而且效率低下。
  • 即使有HashSet行为,我们也会检查每个实例的初始化。它的速度和我一样快,但它仍然是多余的。