我重命名了以下问题:" 为什么我的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;
}
更新 答案如下,我发现以下情况属实:
答案 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;
}
}