通用方法类型和方法参数不匹配

时间:2015-10-29 07:09:36

标签: c# generics types parameters constraints

我只是偶然发现了这一点,我无法解释这一点。说我有那个代码:

public interface IFeature  {  }

public class FeatureA : IFeature { }

class Program
{
  static void Main(string[] args)
  {
    var feature = new FeatureA();
    Load(feature);
  }

  private static void Load(IFeature featureDefinition)
  {
    Activate(featureDefinition);
  }

  private static void Activate<TFeature>(TFeature featureDefinition) where TFeature : IFeature
  {
    var featureType = typeof(TFeature);
    var sameType = featureType == featureDefinition.GetType();
    // sameType == false
  }
}

现在featureType始终为IFeature类型,而不是参数类型featureDefinition。有人可以解释原因吗?

我期待

featureType == featureDefinition.GetType()

是真的......

修改

以上是代码的完整工作示例。

现在我很清楚:参数是非通用的,因此始终是IFeature类型。我想有一个小工作实例的原因:-P

感谢帮助人员!

1 个答案:

答案 0 :(得分:4)

原因是TFeature将是调用Activate函数的类型。这可以是IFeature或实现它的任何类或接口。例如,像这样调用Activate是完全有效的:

Activate<IFeature>(feature);

在这种情况下,编译器使用类型IFeature作为类型参数创建泛型方法Activate,结果是一个完全有效的方法来调用。但是,如果你称之为

Activate<Feature>(feature);

其中Feature实现IFeature,然后编译器当然会使用Feature作为泛型类型参数,并且该方法可以再次调用。

当你只是调用像

这样的方法时,你可能会遇到困难
Activate(feature);

在这种情况下,编译器使用他认为最适合的类型,基于编译器总是这样的静态分析。 不使用对象的运行时类型,因为编译器显然不知道这一点。相反,编译器尝试推断可用作类型参数的最不常见类型。

在这种情况下,编译器将检查静态类型feature实现了哪些接口,如果它与条件匹配,则feature的静态类型用作泛型类型参数。否则,编译器将抛出通用类型不清楚的错误消息。

例如,您始终可以通过显式覆盖静态类型来使编译器忘记静态类型:

object objFeature = feature;
Activate(objFeature);

现在,此代码将引发编译器错误,因为objFeature的静态类型为Object,并且这不符合应该实现IFeature的约束。这与feature的真实类型无关,而feature.GetType()仅在运行时通过// typeof(TFeature) inside Activate returning `IFeature`: IFeature f = new FeatureImpl(); Activate(f); // compiled into Activate<IFeature>(...) // FeatureImpl:FeatureBase:IFeature // typeof(TFeature) inside Activate returning `FeatureImpl`: var f1 = new FeatureImpl(); Activate(f1); // compiled into Activate<FeatureImpl>(...) FeatureBase f2 = new FeatureImpl(); Activate(f2); // compiled into Activate<FeatureBase>(...) 得到。

Inferrence samples:

{ "_id" : 1, "item" : "abc", "price" : 10, "quantity" : 2, "date" : ISODate("2014-03-01T08:00:00Z") }
{ "_id" : 2, "item" : "jkl", "price" : 20, "quantity" : 1, "date" : ISODate("2014-03-01T09:00:00Z") }
{ "_id" : 3, "item" : "xyz", "price" : 5, "quantity" : 10, "date" : ISODate("2014-03-15T09:00:00Z") }
{ "_id" : 4, "item" : "xyz", "price" : 5, "quantity" : 20, "date" : ISODate("2014-04-04T11:21:39.736Z") }
{ "_id" : 5, "item" : "abc", "price" : 10, "quantity" : 10, "date" : ISODate("2014-04-04T21:23:13.331Z") }