The*_*iot 135 c# .net-4.0 covariance winforms
我有一个s()private readonly列表.我稍后在此列表中添加s并将这些标签添加到以下内容中:LinkLabelIList<LinkLabel>LinkLabelFlowLayoutPanel
foreach(var s in strings)
{
_list.Add(new LinkLabel{Text=s});
}
flPanel.Controls.AddRange(_list.ToArray());
Run Code Online (Sandbox Code Playgroud)
Resharper给我一个警告:Co-variant array conversion from LinkLabel[] to Control[] can cause run-time exception on write operation.
请帮我弄明白:
Ant*_*ram 147
这意味着什么
Control[] controls = new LinkLabel[10]; // compile time legal
controls[0] = new TextBox(); // compile time legal, runtime exception
Run Code Online (Sandbox Code Playgroud)
而且更笼统地说
string[] array = new string[10];
object[] objs = array; // legal at compile time
objs[0] = new Foo(); // again legal, with runtime exception
Run Code Online (Sandbox Code Playgroud)
在C#中,您可以引用一个对象数组(在您的情况下,LinkLabels)作为基类型的数组(在本例中,作为一个控件数组).将编译的另一个对象分配给Control数组也是合法的编译时间.问题是该数组实际上不是一个控件数组.在运行时,它仍然是一个LinkLabel数组.因此,赋值或写入将引发异常.
pen*_*tur 14
我会试着澄清Anthony Pegram的回答.
当返回所述类型的值时,泛型类型在某些类型参数上是协变的(例如,Func<out TResult>返回实例TResult,IEnumerable<out T>返回实例T).也就是说,如果某些东西返回实例TDerived,你也可以使用这些实例,就好像它们一样TBase.
当接受所述类型的值(例如Action<in TArgument>接受实例TArgument)时,泛型类型在某些类型参数上是逆变的.也就是说,如果某些东西需要实例TBase,你也可以传递实例TDerived.
接受和返回某种类型的实例(除非在泛型类型签名中定义两次,例如CoolList<TIn, TOut>)的泛型类型在相应的类型参数上不是协变的,也不是逆变的,这似乎是合乎逻辑的.例如,List在.NET 4中定义为List<T>,而不是List<in T>或List<out T>.
某些兼容性原因可能导致Microsoft忽略该参数并使数组在其值类型参数上协变.也许他们进行了分析,发现大多数人只使用数组,就像他们只读一样(也就是说,他们只使用数组初始化器将一些数据写入数组),因此,优点超过了可能的运行时间带来的缺点当有人在写入数组时尝试使用协方差时会出现错误.因此允许但不鼓励.
至于你原来的问题,list.ToArray()创建一个新的LinkLabel[]从原来的列表复制的数值,并且,摆脱(合理的)警告的,你需要在传递Control[]到AddRange.list.ToArray<Control>()将完成工作:ToArray<TSource>接受IEnumerable<TSource>作为其论点并返回TSource[]; List<LinkLabel>实现只读IEnumerable<out LinkLabel>,由于IEnumerable协方差,可以传递给接受IEnumerable<Control>作为其参数的方法.
Chr*_*sic 11
最直接的"解决方案"
flPanel.Controls.AddRange(_list.AsEnumerable());
现在既然你正在改变List<LinkLabel>,IEnumerable<Control>那就不再需要关注,因为无法将一个项目"添加"到一个可枚举的项目中.
该警告是由于这样的事实,你可以添加理论上一个Control比其他LinkLabel的LinkLabel[]通过Control[]引用.这会导致运行时异常.
转换发生在这里因为AddRange需要a Control[].
更一般地说,如果您不能按照刚刚概述的方式随后修改容器,则将派生类型的容器转换为基本类型的容器是安全的.数组不满足该要求.
问题的根本原因在其他答案中已正确描述,但要解决警告,您始终可以写:
_list.ForEach(lnkLbl => flPanel.Controls.Add(lnkLbl));
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
30668 次 |
| 最近记录: |