M.B*_*ock 1 c# generics ienumerable typecast-operator
希望这不是一个骗局,找不到任何相关的在线
我在以下扩展方法中遇到奇怪的编译时错误:
public static TCol AddRange<TCol, TItem>(this TCol e, IEnumerable<TItem> values)
where TCol: IEnumerable<TItem>
{
foreach (var cur in e)
{
yield return cur;
}
foreach (var cur in values)
{
yield return cur;
}
}
Run Code Online (Sandbox Code Playgroud)
错误:
'TestBed.EnumerableExtensions.AddRange(TCol,System.Collections.Generic.IEnumerable)'的主体不能是迭代器块,因为'TCol'不是迭代器接口类型
这是否意味着编译器在确定方法是否符合yield return使用条件时不考虑通用约束?
我在一个使用泛型参数定义集合的类中使用此扩展方法.类似的东西(除了一些类型转换操作符):
public class TestEnum<TCol, TItem>
where TCol : class, ICollection<TItem>, new()
{
TCol _values = default(TCol);
public TestEnum(IEnumerable<TItem> values)
{
_values = (TCol)(new TCol()).AddRange(values);
}
public TestEnum(params TItem[] values) : this(values.AsEnumerable()) { }
...
}
Run Code Online (Sandbox Code Playgroud)
反过来,使用像(记得我定义了类型转换操作符):
TestEnum<List<string>, string> col = new List<string>() { "Hello", "World" };
string someString = col;
Console.WriteLine(someString);
Run Code Online (Sandbox Code Playgroud)
最初,我的扩展方法看起来像:
public static IEnumerable<TItem> AddRange<TItem>(this IEnumerable<TItem> e, IEnumerable<TItem> values)
{
...
}
Run Code Online (Sandbox Code Playgroud)
哪个编译但导致:
未处理的异常:System.InvalidCastException:无法转换类型为"<AddRange> d _6
1[System.String]' to type 'System.Collections.Generic.List1 [System.String]"的对象.
有没有其他方法可以做到这一点?
根据要求,这是一个小样本:
class Program
{
public static void Main()
{
TestEnum<List<string>, string> col = new List<string>() { "Hello", "World" };
string someString = col;
Console.WriteLine(someString);
}
}
public class TestEnum<TCol, TItem>
where TCol : class, ICollection<TItem>, new()
{
TCol _values = default(TCol);
public TestEnum(IEnumerable<TItem> values)
{
_values = (TCol)(new TCol()).AddRange(values);
}
public TestEnum(params TItem[] values) : this(values.AsEnumerable()) { }
public static implicit operator TItem(TestEnum<TCol, TItem> item)
{
return item._values.FirstOrDefault();
}
public static implicit operator TestEnum<TCol, TItem>(TCol values)
{
return new TestEnum<TCol, TItem>(values);
}
}
public static class EnumerableExtensions
{
public static IEnumerable<TItem> AddRange<TItem>(this IEnumerable<TItem> e, IEnumerable<TItem> values)
{
foreach (var cur in e)
{
yield return cur;
}
foreach (var cur in values)
{
yield return cur;
}
}
}
Run Code Online (Sandbox Code Playgroud)
要重新编译编译时异常:
class Program
{
public static void Main()
{
TestEnum<List<string>, string> col = new List<string>() { "Hello", "World" };
string someString = col;
Console.WriteLine(someString);
}
}
public class TestEnum<TCol, TItem>
where TCol : class, ICollection<TItem>, new()
{
TCol _values = default(TCol);
public TestEnum(IEnumerable<TItem> values)
{
_values = (TCol)(new TCol()).AddRange(values);
}
public TestEnum(params TItem[] values) : this(values.AsEnumerable()) { }
public static implicit operator TItem(TestEnum<TCol, TItem> item)
{
return item._values.FirstOrDefault();
}
public static implicit operator TestEnum<TCol, TItem>(TCol values)
{
return new TestEnum<TCol, TItem>(values);
}
}
public static class EnumerableExtensions
{
public static TCol AddRange<TCol, TItem>(this TCol e, IEnumerable<TItem> values)
where TCol : IEnumerable<TItem>
{
foreach (var cur in e)
{
yield return cur;
}
foreach (var cur in values)
{
yield return cur;
}
}
}
Run Code Online (Sandbox Code Playgroud)
让我们简化一下:
static T M() where T : IEnumerable<int>
{
yield return 1;
}
Run Code Online (Sandbox Code Playgroud)
为什么这是非法的?
出于同样的原因,这是非法的:
static List<int> M()
{
yield return 1;
}
Run Code Online (Sandbox Code Playgroud)
编译器只知道如何将M转换为返回的方法IEnumerable<something>.它不知道如何将M转换为返回其他任何东西的方法.
您的泛型类型参数T可以是List<int>实现的无限多种其他类型IEnumerable<T>.C#编译器不知道如何将该方法重写为一个返回它不知道的类型的方法.
现在,关于你的方法:首先是TCol的功能是什么?为什么不说:
public static IEnumerable<TItem> AddRange<TItem>(
this IEnumerable<TItem> s1, IEnumerable<TItem> s2)
{
foreach(TItem item in s1) yield return item;
foreach(TItem item in s2) yield return item;
}
Run Code Online (Sandbox Code Playgroud)
顺便提一下,这种方法已经存在; 它被称为"康卡特".
我不确定你想要完成什么,你的方法当然看起来不像AddRange(),因为它不会给任何集合添加任何东西.
但是如果你编写一个迭代器块,它将返回一个IEnumerable<T>(或IEnumerator<T>).它返回的实际运行时类型是编译器生成的,并且无法强制它返回某些特定的集合,例如List<T>.
从您的示例中,AddRange()根本不返回List<T>,这就是您无法将结果强制转换为该类型的原因.而且没有办法让迭代器块返回List<T>.
如果要创建一个向集合添加内容的方法,可能意味着您需要调用Add(),而不是从方法返回其他一些集合:
public static void AddRange<T>(
this ICollection<T> collection, IEnumerable<T> items)
{
foreach (var item in items)
collection.Add(item);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1716 次 |
| 最近记录: |