【问题标题】:How to add a C# generic type constraint on another generic base class?如何在另一个泛型基类上添加 C# 泛型类型约束?
【发布时间】:2013-11-26 13:28:01
【问题描述】:

我已多次阅读有关 C# 泛型类型参数约束的 MSDN 文档,但我无法弄清楚如何做到这一点,或者确定它是否可能。

假设我有一个这样的通用基类:

public abstract class Entity<TId> { ... }

这个抽象基类没有任何类型约束,TId 可以是任何东西——结构、类等。

现在说我有一个泛型接口方法,我想将方法​​上的泛型类型约束到上面的类:

public interface ICommandEntities
{
    void Update<TEntity>(TEntity entity) where TEntity : ?????;
}

我可以编译这个:

public interface ICommandEntities
{
    void Update<TEntity, TId>(TEntity entity) where TEntity: Entity<TId>
}

...但是我需要在执行该方法时显式添加两个 T1 ant T2 通用参数:

commander.Update<AbcEntity, string>(abcEntity);

如果可能的话,我想让编译器推断一切,这样我就可以执行这样的方法:

commander.Update(abcEntity);

这个活动可以吗?到目前为止,我可以让它工作的唯一方法是在泛型基类之上添加一个空的非泛型基类,并将其用作方法的类型约束:

public abstract Entity {}

public abstract EntityWithId<TId> : Entity { ... }

public interface ICommandEntities
{
    void Update<TEntity>(TEntity entity) where TEntity : Entity;
}

commander.Update(abcEntity);

...但是我最终得到了一个非常无用的类,它充当标记接口。这是摆脱这种泛型类和接口方法设计的唯一方法吗?还是我在这里遗漏了什么?

【问题讨论】:

  • void DoAbc&lt;TForInterface&gt;(BaseClass&lt;TForInterface&gt; impl); 可以,但我不确定这是否是您要找的。​​span>
  • 我不明白的是T2既不是输入参数也不是返回值。
  • 您是否考虑过将接口设为通用?
  • void doAbc&lt;T1&gt;(BaseClass&lt;T1&gt; impl) 呢?
  • 在您更新的示例中,我不明白为什么当您有一个基类时您希望您的更新对两个泛型类型进行操作。 void Update&lt;TId&gt;(EntityWithId&lt;TId&gt; entity); 是一个足够好的约束,不是吗? EntityWithId 是 Entity,无需对附加类型参数施加泛型约束。

标签: c# generics type-constraints


【解决方案1】:

检查是否可以编译后,我会将其升级为答案。

根据您的问题和 cmets,您希望参数为 Entity&lt;Something&gt;。参数化的类型不需要直接作为类型使用,可以用来参数化参数。

就这样吧

 public void Update(Entity<T1> entity) where ....

【讨论】:

  • ... 好吧,我想我现在明白了,这样做,如果我使用基类作为方法 arg,接口方法不需要任何泛型类型约束。对吗?
  • 您所做的是定义您想要的参数类型。你想要Entity&lt;X&gt;,所以你只需要参数化X。不要忘记协方差的问题,也许值得将类型参数标记为in。
  • Entity 上的泛型虽然没有限制。它可以是string、int、long,也可以是XyzCompositeId 类。我不认为我想在这里应用任何协变或逆变。
  • 我不知道我是否理解你。 X 将具有在 Entity 参数类型中定义的约束(您提供的代码中没有)。此外,您可以将所需的约束指定为IEntityCommand.Upload 参数类型。我不知道您是要求确认没有约束还是要定义任何约束。
  • 对,很抱歉造成混乱。我不希望对接口方法有任何额外的约束。我只是不希望任何代码能够调用传递不从Entity&lt;X&gt; 派生的类的实例的方法。所以你是对的,我可以让这个方法的 X 协变。
【解决方案2】:

简单的选择是更改ICommandEntities 的签名:

public interface ICommandEntities
{
    void Update<TId>(Entity<TId> entity)
}

这实际上给出了您所追求的相同约束。

【讨论】:

    【解决方案3】:

    如 cmets 中所述,您只需将参数类型设为 BaseClass&lt;T&gt;

    class Program
    {
        static void Main( string[] args )
        {
            ITest x = new TestClass();
    
            Console.WriteLine( x.GetTypeArgTypeFrom( new BaseClass<int>() ) );
    
            Console.ReadKey();
    
        }
    }
    
    public class BaseClass<T>
    {
        public Type GetTypeArgType()
        {
            return typeof( T );
        }
    }
    
    public interface ITest
    {
        Type GetTypeArgTypeFrom<T>( BaseClass<T> bct );
    }
    
    public class TestClass : ITest
    {
        public Type GetTypeArgTypeFrom<T>( BaseClass<T> bct )
        {
            return bct.GetTypeArgType();
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-06-28
      • 1970-01-01
      • 1970-01-01
      • 2019-06-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多