【问题标题】:C# generics contraints propagationC# 泛型约束传播
【发布时间】:2013-01-22 01:04:22
【问题描述】:

这个例子是对实际问题的简化,但我怎样才能让它编译呢?我希望泛型约束能够传播。

既然 T 是一个 TClass 而 TClass 是一个类,为什么 T 不是一个类?

public class MyClass<TClass> where TClass : class 
{
    public void FuncA<Ta>() where Ta : class
    {
    }

    public void FuncB<Tb>() where Tb : TClass
    {
    }

    public void Func<T>()
        where T : TClass
    {
        FuncA<T>();
        FuncB<T>();
    }
}

编辑

这确实有效。 Eric Lippert 让我思考,谢谢。

由于 T 是一个 TClass,而 TClass 是一个 TAnotherType,所以 T 实际上是 TAnotherType。

public class MyClass<TClass, TAnotherType> where TClass : TAnotherType
{
    public void FuncA<Ta>() where Ta : TClass
    {
    }

    public void FuncB<Tb>() where Tb : TAnotherType
    {
    }

    public void Func<T>()
        where T : TClass
    {
        FuncA<T>();
        FuncB<T>();
    }
}

【问题讨论】:

    标签: c# generics


    【解决方案1】:

    既然TTClassTClass 是一个类,为什么T 不是一个类?

    前提 1:“Bob Smith”是一个专有名称。

    前提2:“一个专有名词”是一个三字句子片段。

    结论:因此“Bob Smith”是一个三字的句子片段。

    这个逻辑显然是不正确的。

    前提 1:TTClass

    前提 2:TClass 是一个类

    结论:因此T是一个类。

    出于同样的原因,该逻辑是不正确的。

    在这两种情况下,我们都使用“is”来表示两个前提中的两个完全不同的事物。在第一个前提中,“is”用来表示“这两个事物之间具有is-a-kind-of的关系”。在第二个前提中,“是”用于表示“这一事物具有特定的特征”。

    你可以通过简单地替换TTClass来更直接地看出你的逻辑是错误的:

    前提1:intSystem.ValueType

    ('is' 表示'有子类关系')

    前提2:System.ValueType是一个类

    ('is'表示'具有特定的属性,即被引用复制)

    结论:因此int是一个类。

    再一次,我们得出了一个错误的结论,因为“是”以两种不一致的方式使用。

    另一个例子:

    前提 1:一个汉堡总比没有好。

    前提 2:没有什么比一块好牛排更好的了。

    结论:从传递性来看,汉堡比好牛排要好。

    最后,有关此主题的更多想法,请参阅我最近的文章:

    http://ericlippert.com/2011/09/19/inheritance-and-representation/

    【讨论】:

    • 如果它是一个好汉堡,它可能是。与厨师交朋友,您会惊讶于汉堡包的美味! :)
    • 如果我们定义TClass : class,我们说TClass必须是一个引用类型。如果我们说T : TClass,我们说T 类型必须是为TClass 传递的类型的派生/实现(或相同)。既然TClass仅限于引用类型,那为什么不能将T推断为引用类型呢?你能举个例子说明情况不是这样吗?还是我完全搞错了?
    • @Rob:我确实举了一个例子,但事实并非如此。再读一遍答案。为什么你认为从引用类型派生的类型必须是引用类型?继承共享成员。其他属性不被继承。鸭嘴兽是动物,动物是六个字母的词,那么鸭嘴​​兽是六个字母的词?我不这么认为。
    • +1,因为最后一条评论比原来的帖子解释得更好;)
    • @MatteS:“is”和“to be”是同一个动词。您使用“成为”来表示两种不同的事物。停止模棱两可地使用动词。 “T 被限制为从 TCLass 派生的类型。TClass 被限制为通过引用复制的类型。”现在不及物性很明显;不要求从引用类型派生的类型也通过引用复制; derivation 不会保留 copy-by-reference 属性,就像它保留其他属性(例如名称的长度)一样。
    【解决方案2】:

    问题在于T 不一定是引用类型。考虑:

    MyClass<IFormattable> foo = new MyClass<IFormattable>();
    MyClass.Func<int>();
    

    这会尝试调用FuncA&lt;int&gt;,但int 不遵守: class 约束。

    所以基本上你还需要将: class 约束添加到Func&lt;T&gt;

    public void Func<T>() where T : class, TClass
    

    【讨论】:

    • public void Func&lt;T&gt;() where T : TClass, class 此代码无法编译,应更改类和 TClass 位置。
    • 正如 Saeed 的回复中所述,显然你必须在 where T : class, TClass 中做。
    • @invisible: 但是int 实现了IFormattable
    • 我想就是这样,我希望调用 MyClass.Func();如果约束会传播,则不编译,但显然它们不会。
    • @MatteS:Func&lt;int&gt;() 的哪一点不会编译? int 可转换为 IFromattable,这就是约束所需的全部内容。
    【解决方案3】:

    为了编译这个做;

    public void Func<T>()
        where T :class, TClass
    {
        FuncA<T>();
        FuncB<T>();
    }
    

    因为 FunA 的输入只是一个类而不是特殊类。

    【讨论】:

    • 谢谢!在旁注中,有趣的是我不能在哪里做 T :TClass,类
    • @MatteS 正如我所写,你应该这样做 T:class, TClass 而不是 T:TClass, class
    【解决方案4】:

    我不确定以下是否是您的代码或复制/粘贴更改中的拼写错误(为简化起见):

    public void FuncA<Ta>() where Ta : class //TClass instead of class?
    {
    }
    

    【讨论】:

    • 他在问为什么T : TClass 约束不满足Ta : classTClass 本身就是class
    • 其他人已经回答了这部分,我想我会尝试一下,也许是一个错字。
    【解决方案5】:

    看起来你只是好奇为什么你不能这样做。而且您对这样的工作示例不感兴趣:

    public class MyClass<TClass> where TClass : class
    {
        public void FuncA<Ta>() where Ta : class
        {
        }
    
        public void FuncB<Tb>() where Tb : TClass
        {
        }
    
        public void Func()
        {
            FuncA<TClass>();
            FuncB<TClass>();
        }
    }
    

    【讨论】:

      【解决方案6】:

      你们都说 T : TClass 和 TClass : class 并不意味着 T : class。 好的,如果我给你:

      public MyClass<TClass> where TClass : class
      {
           public void MyFunc<T>() where T : TClass
           {
               // who cares ?
           }
      }
      

      您能否提供一个示例,其中您使用 T 的类型不是一个类,因为我真的不明白 T : TClass 和 TClass : class 不意味着 T : 类。请不要试图解释奇怪的事情,只用一个例子就可以证明这一点。

      【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多