【问题标题】:T does not contain the definition for RowKeyT 不包含 RowKey 的定义
【发布时间】:2012-07-23 14:46:54
【问题描述】:

我正在尝试创建一个泛型类:

public class ClassName<T>
{
    public T AccessEntity(string id)
    {
        return (from e in ServiceContext.CreateQuery<T>(TableName)
                where e.RowKey == id // error here!
                select e).FirstOrDefault();
    }
}

在这段代码中,我收到以下错误:

T 不包含 RowKey 的定义

但是将在运行时替换 T 的参数具有 RowKey 的定义。可能是因为编译器在编译时没有在 T 中获得 RowKey 的定义,这就是我收到此错误的原因。谁能告诉我如何解决这个问题?

【问题讨论】:

  • 作为评论 - 我赞成正确答案之一:编译器不关心 T 稍后会是什么。它关心它在编译时知道的内容,这意味着您可以创建 ClassName 并且 Dumbo 没有 RowKey -> 错误。添加约束 ;)
  • Pro 说明了 TomTom 的观点:在 c# 中,您可以编写一个类型在运行时,并为新类型调用泛型类型——只要它满足约束,它'会工作的。这与 c++ 模板非常不同。

标签: c# .net generics compiler-errors


【解决方案1】:

为此,您需要一个接口约束:

interface IHazRowKey {
     string RowKey { get; } 
}

并指定此限制:

public class classname<T> where T : IHazRowKey {...}

并在每个实现上指定: IHazRowKey

public class Foo : IHazRowKey {....}

现有的RowKey 成员应该匹配它(假设它是一个属性,而不是一个字段),因此您不需要添加任何其他额外代码。如果它实际上是一个字段(它不应该是,IMO),那么:

public class Foo : IHazRowKey {
    string HazRowKey.RowKey { get { return this.RowKey; } }
    ...
}

【讨论】:

  • 不应该是ICanHazRowKey吗? :)
  • 感谢您的回答,但我作为通用类实现的类已经从另一个类驱动,抱歉没有提到这个问题。意味着它类似于: public class ClassName : Base
  • @Tom 不会改变任何东西;允许多接口继承和单类继承,
  • 是否可以不在类实现中添加: IHazRowKey?例如。我想创建一个通用函数来切换控件的隐藏/扩展(当然,如果定义了相应的方法),当然,这里没有办法修改微软的代码。
  • @Hi-Angel 您是在问“可以使现有类实现接口”吗?如果是这样:不。你必须把它包起来,装饰风格。当然,除非它只是在同一程序集中生成代码,在这种情况下:“部分类”
【解决方案2】:

C++ 模板和 C# 泛型之间有一个主要区别:如果编译器在编译泛型类时不知道 T 上的方法,则传递哪些类来实例化泛型并不重要,或者方法,它会给你一个错误。这是因为 C# 需要能够将通用代码与其实例化位置分开编译(请记住,C# 中没有标头)。

您可以定义一个接口,并将T 限制为它,以便在泛型中使用属性和方法。将RowKey 添加到您的界面,并将where T : myinterface 添加到您的泛型声明中。

【讨论】:

    【解决方案3】:

    你需要定义constraint来解决这个问题:

    public interface IHasRowKey
    {
       string RowKey {get;}
    }
    
    public class classname<T> where T : IHasRowKey
    {
    
    }
    

    【讨论】:

      【解决方案4】:
      class YourClass // or extract an interface
      {
          public string RowKey { get; set; }
      }
      
      class YourGeneric<T> where T : YourClass
      {
          // now T is strongly-typed class containing the property requested
      }
      

      【讨论】:

        【解决方案5】:

        我的案例不能使用接口来包含 RowKey,因为我有两个具有不同属性和方法的类。我不能只是将它们合并并将这些属性和方法放入一个包装器接口或类中,因为它失去了使用泛型类的目的。我的解决方案是使用泛型类的反射。例如:

        public class ClassName<T> {
            private T _genericType;
            public ClassName(T t) {
                _genericType = t;
            }
        
            public void UseGenericType() {
                // Code below allows you to get RowKey property from your generic 
                // class type param T, cause you can't directly call _genericType.RowKey
                PropertyInfo rowKeyProp = _genericType.GetType().GetProperty("RowKey");
                if(rowKeyProp != null) { // if T has RowKey property, my case different T has different properties and methods
                    string rowKey = rowKeyProp.GetValue(_genericType).ToString();
                    // Set RowKey property to new value
                    rowKeyProp.setValue(_genericType, "new row key");
                }
            }
        }
        

        这里是对PropertyInfo类http://msdn.microsoft.com/en-us/library/System.Reflection.PropertyInfo_methods(v=vs.110).aspx的引用

        【讨论】:

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