无法转换类型' T'到了'?

时间:2014-04-18 05:22:52

标签: c# .net .net-4.0 covariance generic-collections

我重命名了以下问题:" 为什么我的UpCast()不能编译为实例方法,而是作为扩展名?"对未来憔悴的冒险家来说更有用的东西。

我最初开始实现UpCast()作为实例方法,但最终还是对编译器消息感到惊讶,这些消息似乎没有意义。最初的问题如下,更新。

我有一个从ObservableCollection派生的容器类。刚才我试着写一个UpCast<>通用方法,而不是写:

Columns = new MegaList<DbTableColumn>();
Columns.AddRange( oracleDictionary.ListTableColumns(tableName) );  // IEnumerable<OracleColumn>

// or

(v.Columns = new MegaList<DbTableColumn>()).AddRange( oracleDictionary.ListTableColumns(tableName) );

// I could instead write
Columns = oracleDictionary.ListTableColumns(tableName).UpCast<DbTableColumn>();

MegaList是ObservableCollection,带有一些额外的便利方法,我不会在这里显示。由于ObservableCollection没有ConvertAll(),我尝试了这个。

基本上,为什么以下的实例方法没有编译,但我可以实现看似等效的扩展方法(在底部列出),它呢?

 public class MegaList<T> : ObservableCollection<T>
 {
    // ...rest of class snipped...

    public ObservableCollection<TBase> UpCast<TBase, T>()
       where TBase: class
       where T : TBase
    {
       var listUpcast = new ObservableCollection<TBase>();
       foreach (T t in this.Items) <-- Error 14 Cannot convert type 'T' to 'T' ??? Excuse me?
          listUpcast.Add(t);
       return listUpcast;
    } 
 }

我认为以下内容是等效的。只需交换&#34;这个&#34; OberservableCollection.Items属性的参数,都保持类型T. 我特别困惑,因为类型约束表明&#34; T必须是TBase&#34;

    static public ObservableCollection<TBase> UpCast<TBase, T>(this ObservableCollection<T> list)
      where TBase : class
      where T : TBase
    {
       var listUpcast = new ObservableCollection<TBase>();
       foreach (var t in list)
          listUpcast.Add(t);
       return listUpcast;
    } 

更新 答案如下,我发现以下情况属实:

  1. C#具有泛型类型参数阴影,就像常规一样 字段/参数阴影。
  2. 我不能在a中写一个类型约束 使用封闭类中的类型参数的泛型方法, 因为(1)而我不认为有一种方法可以在类型约束中引用类型,其中T是泛型类型参数。

2 个答案:

答案 0 :(得分:1)

我不想回答我自己的问题,但是这个让我感到难过,在视觉上它没有意义,没有其他人解释过它。

经过一夜的睡眠,我突然意识到这只是通用的参数阴影。泛型参数的阴影显然存在(我不知道这个,因为我没有多写内部类),并且像标准参数一样工作。因此,即使T是外部类中的类型参数,编译器也会将内部方法(或类)中的T视为T2,并且它们不是同一类型,因此相应于“T”的错误不能分配给T “因为我试图用T迭代一个IList(如果你纯粹从一个符号级别看它,它应该工作)。错误是:

public class MegaList<T> : ObservableCollection<T>
{
   public ObservableCollection<TBase> UpCast<TBase, T>()  // <-- this T isn't outer T
      where TBase : class
      where T : TBase
   {
      var listUpcast = new ObservableCollection<TBase>();
      foreach (T t in this.Items)  // <-- error: Argument type 'T' is not assignable to parameter type 'TBase'
        listUpcast.Add(t);
      return listUpcast;
   }
}

由于我必须提供T作为通用参数,我不能将它约束在@hvd支持的内部方法上,所以除非有人知道我没有的语法,否则我会放弃这个并且要么在方法中使用强制转换,要么坚持使用扩展方法来限制它。

老实说,我无法确定这是一个功能还是限制。我想这取决于你的观点。希望这有助于其他人。至少C#编译器应该改进错误消息,以便类型之间存在明显的差异。鉴于在外部范围内声明了一个(可以这么说),我不明白为什么类型应该被列为Foo.T vs Foo.T,我认为内部T将在外部类的符号命名空间中,因此有一个不同的限定类型名称,如MegaList.T vs MegaList.UpCast.T。

答案 1 :(得分:0)

UpCast方法的定义不应该是

public class MegaList<T> : ObservableCollection<T>
{
    // ...rest of class snipped...

    public ObservableCollection<TBase> UpCast<TBase>()
    {
        var listUpcast = new ObservableCollection<TBase>();
        foreach (var t in this.Items)
            listUpcast.Add((TBase)t); // <-- error: Argument type 'T' is not assignable to parameter type 'TBase'
        return listUpcast;
    }
}