具有多个类约束的C#泛型类型

Mat*_*att 10 c#

TL; DR

我想用C#编译

public void some_method< T >() where T : class1, class2

这可能吗?


完整的背景

除了一个参数外,我有两个相同的方法.

public SignInResponseMessage Generate(SignInRequestMessage request, (X509Certificate2 || WindowsPrincipal) principal, Uri requestUri)
{
    SignInResponseMessage response = null;
    ClaimsIdentity identity = null;

    if (principal != null)
    {
        identity = CreateSubject(principal);
        response = Generate(request, requestUri, identity);
    }
    else
    {
        throw new ArgumentNullException("principal");
    }

    return response;
}
Run Code Online (Sandbox Code Playgroud)

我正在复制这种方法,它让我内心畏缩,因为我真的想做这个DRY.环顾四周,这个文档看起来很有希望,但它只允许我添加一个类约束.我在第二节课上得到以下错误:

错误1类类型约束"class2"必须位于任何其他约束之前

如果WindowsPrincipal并且X509Certificate2是我编写的两个类,我可以轻松地使它们实现相同的界面,我会很高兴,但这不是一个选项.

有没有办法完成我想做的事情?

如果没有,我想更多地了解使这不可能的潜在机制.

tig*_*ars 7

我担心这可能会导致问题,找出实际调用的方法.想象一下,如果其中一个类继承自另一个类,并且该方法有一个覆盖!?

有关原因的完整说明,请参阅"钻石问题"

如果你想解决它.您可以使用适配器设置公共共享接口,然后使用它.

interface IAdaper {
    SomeMethod();
}

class AdapterOne : IAdapter {
    TypeOneToCall  _one;

    public AdapterOne (TypeOneToCall one) {
        _one = one;
    }

    public SomeMethod() {
        return _one.SomeMethod();
    }
}

class AdapterTwo : IAdapter {
    TypeTwoToCall _two;

    public AdapterTwo (TypeTwoToCall two) {
        _two = two;
    }

    public SomeMethod() {
        return _two.SomeMethod();
    }
}

class Generic<T> where T : IAdapter {

    // Your implementation here.
}
Run Code Online (Sandbox Code Playgroud)

  • 创建抽象(`IAdapter`)的建议是个好主意.在这种情况下,你甚至不需要`Generic`类是通用的,因为它不需要知道`IAdapter`背后的内容. (2认同)

小智 6

如果将方法作为参数传递,则T可以是任何值:

  public SignInResponseMessage Generate<T>(SignInRequestMessage request, 
                                          Func<T, ClaimsIdentity> createSubject, 
                                          T principal, 
                                          Uri requestUri)
  {
      SignInResponseMessage response = null;
      ClaimsIdentity identity = null;

      if (principal != null)
      {
          identity = createSubject(principal);
          response = Generate(request, requestUri, identity);
      }
      else
      {
          throw new ArgumentNullException("principal");
      }

      return response;
  }
Run Code Online (Sandbox Code Playgroud)

所以重用方法:

  var r1 = Generate<X509Certificate2>(request, CreateSubject, certificate, uri);
  var r2 = Generate<WindowsPrincipal>(request, CreateSubject, principal, uri);
Run Code Online (Sandbox Code Playgroud)