自引用通用参数

时间:2019-02-17 14:58:14

标签: c# .net generics typing

例如,我有以下课程:

1。

class MyClass1
{
    public MyClass1 Method()
    {
        ...
        return new MyClass1();
    }
}

class MyClass2
{
    public MyClass2 Method()
    {
        ...
        return new MyClass2();
    }
}

这些方法具有相同的主体,这就是为什么我要提取代码并重复使用。

2。

abstract class MyClass
{

    protected void Method()
    {
        ...
    }
}

class MyClass1 : MyClass
{

    public MyClass1 Method()
    {
        base.Method();
        return new MyClass1();
    }
}

class MyClass2 : MyClass
{
    public MyClass2 Method()
    {
        base.Method();
        return new MyClass2();
    }
}

但是,由于存在许多此类方法,因此最好将这些方法移至基类MyClass

3。

abstract class MyClass<T>: where T : MyClass<T>
{
    protected abstract T Create();

    public T Method()
    {
        ...
        return Create();
    }
}

class MyClass1 : MyClass<MyClass1>
{
    protected override MyClass1 Create() => new MyClass1();
}

class MyClass2 : MyClass<MyClass2>
{
    protected override MyClass2 Create() => new MyClass2();
}

它工作正常,但是合同看起来太奇怪了。当然,我可以提取类似IMyInterface的东西,然后返回它而不是类。但是,我必须保留原始合同,因为它也包含特定的方法。

更新:因此,奇怪的是粗体-类 MyClass1 :MyClass << strong> MyClass1 >

3 个答案:

答案 0 :(得分:4)

这是通常的所谓的自类型问题(您有Method()应该返回与调用它的对象相同的类型)。您的解决方案3看起来很像F边界量化。但是,这是C#,而不是Java,因此我们可以使用扩展类做得更好。

通过添加绑定在MyClass上的where T : MyClass,可以确保仅在T的子类上调用这些方法。

// Put all your shared methods in generic classes in here.
public static class MyMethods
{
    public static T Method<T>(this T x) where T : MyClass
    {
        ...
    }
}

您的类变化不大,只是它们根本不需要提及Method(或其他共享方法)。

public abstract class MyClass
{
    ...
}

public class MyClass1 : MyClass
{
    ...
}

public class MyClass2 : MyClass
{
    ...
}

答案 1 :(得分:3)

是的,只有一个创建方法看起来有点怪异。

因为您有两个类MyClass1和MyClass2,它们具有特定的不同方法,并且只有基本方法是常见的(您将它们放在基类中),所以我认为您可以使用Abstract工厂模式。

public class ClassFactory: IClassFactory
{
    public MyClass Create()
    {
         if (some condition)
              return new MyClass1;
         return new MyClass2;
    }
}

class MyClass
{
    protected string CommonLogic()
    {
         //common logic 
         return string;
    }

}

class MyClass1 : MyClass
{
    public object SpecificMethod()
    {
        CommonLogic();
        .....
    }

}

class MyClass2 : MyClass
{
    public object SpecificMethod2()
    {
        CommonLogic();
        .....
    }
}

在这种情况下,您将没有重复的代码,并且您将拥有某个类,该类将负责创建类并知道何时以及哪个类返回。 +您将在这里轻松使用IoC。

希望我的回答对您有所帮助。

答案 2 :(得分:0)

在一些罕见的情况下,可能需要自引用类型约束,但是我不相信这是其中之一。

似乎您要使用工厂(创建)模式,并使这些工厂返回不同的具体类型。但是同时,您说的是这些具体类型都有一些共同点,由基类指定。

常规方法是在接口(如您建议的IMyInterface)中定义通用功能,然后从Create方法返回该功能。这将捕获具体类的多态方面。然后的问题是如何捕获在具体类型中实现的其他方法。为此,只需定义其他接口即可捕获由多个以上具体类实现的各种功能集群。

在您完成此操作后,如果还剩下一点点和单调的功能,我想说,通过转换来处理它们是最简单的-那时,功能仅是其中之一具体课程。如果您想闭着眼睛飞行,可以使用“动态”类型而不是强制类型。

此外,通常在对象实例中未定义Create方法,换句话说,通常对象不是它们自己的工厂。通常,它们是静态的或在单独的工厂类中。在当前情况下,进行一些反思可以帮助您处理具有多个派生类型的事实。除了下面显示的内容外,还有多种方法可以做到这一点。

所以……也许是这样的:

public interface ICommonFunctionality
{
    void SomethingThatEveryoneCanDo();
    // ... other common functionality
}

public interface IAdditionalFunctionality1
{
    void SomethingThatAFewCanDo();
    // ... other special functionality
}
public interface IAdditionalFunctionality2
{
    void SomethingThatOthersCanDo();
    // ... other special functionality
}

public class MyClass : ICommonFunctionality
{
    static public ICommonFunctionality Create(Type derivedType)
    {
        if (!typeof(ICommonFunctionality).IsAssignableFrom(derivedType)) { throw new ArgumentException(); }
        return derivedType.CreateInstance() as ICommonFunctionality;
    }

    virtual public void SomethingThatEveryoneCanDo() { /* ... */  }
}

public class MyClass1 : MyClass, IAdditionalFunctionality1
{
    public void SomethingThatAFewCanDo() { /* ... */ }
}

public class MyClass2 : MyClass, IAdditionalFunctionality1, IAdditionalFunctionality2
{
    public void SomethingThatAFewCanDo() { /* ... */ }
    public void SomethingThatOthersCanDo() { /* ... */ }
}

public class MyClass3 : MyClass, IAdditionalFunctionality2
{
    public void SomethingThatOthersCanDo() { /* ... */ }
}

public static class TypeHelpers
{
    public static object CreateInstance(this Type type, bool required = true)
    {
        System.Reflection.ConstructorInfo ctor = type.GetConstructor(Type.EmptyTypes);
        if (required && ctor == null) { throw new InvalidOperationException("Missing required constructor."); }
        return ctor?.Invoke(null);
    }
}

P.S。我已经将基类方法设为虚拟,这取决于您的情况是可选的。