C# LINQ铸造问题

C# LINQ铸造问题,c#,linq,C#,Linq,我有一个winform,有两个复选框和一个按钮。在两个复选框的CheckedChanged事件中,我给出了以下代码 //Enable the button if any of the checkbox is checked var ChkBoxes = from CheckBox ctrl in this.Controls where ctrl is CheckBox select ctrl; button1.Enabled = ChkBoxes.Any(c =&

我有一个winform,有两个复选框和一个按钮。在两个复选框的CheckedChanged事件中,我给出了以下代码

//Enable the button if any of the checkbox is checked
var ChkBoxes = from CheckBox ctrl in this.Controls 
               where ctrl is CheckBox select ctrl;
button1.Enabled = ChkBoxes.Any(c => ((CheckBox)c).Checked);
但是,当选中任一复选框时,我得到一个错误“无法将类型为“System.Windows.Forms.Button”的对象强制转换为类型为“System.Windows.Forms.CheckBox”。”执行第二行代码时出现错误

后来我将代码更新为以下内容,效果很好。我所做的唯一更改是将ctrl类型从复选框修改为控件

var ChkBoxes = from Control ctrl in this.Controls 
               where ctrl is CheckBox select ctrl;
button1.Enabled = ChkBoxes.Any(c => ((CheckBox)c).Checked);

我的问题是,在这两种情况下,我只返回checkbox类型的控件,那么为什么会出现强制转换错误。有人能解释一下这是怎么回事吗?

因为“this.Controls”在表单上包含所有控件。where条款尚未适用

因此,在Linq可以使用where子句之前,它尝试将对象强制转换为您指定的类型,该类型最初是复选框。当它到达一个按钮时,演员阵容失败了

在您的修复程序中,您正确使用了控件类型,这是有效的,因为“this.Controls”中的所有对象都是控件,然后Linq可以应用Linq语句的其余部分。

而不是使用:

var ChkBoxes = from CheckBox ctrl in this.Controls where ctrl is CheckBox select ctrl;
尝试使用进行筛选:

var chkBoxes = this.Controls.OfType<CheckBox>();
button1.Enabled = chkBoxes.Any(c => c.Checked); // No cast required now
var chkBoxes=this.Controls.OfType();
button1.Enabled=chkBoxes.Any(c=>c.Checked);//现在不需要演员

在第一个示例中,不会引发异常,因为Linq查询使用所谓的“微分”或“惰性”求值

它只是在运行第二行时才开始为您获取值,该行称为“枚举”查询


编辑-另一个答案中的OfType extension方法可能是最好的选择。

因为它会转换为如下内容:

IEnumerable<CheckBox> ChkBoxes = this.Controls.Cast<CheckBox>().Where(ctrl => ctrl is CheckBox).Select(o => o);

Controls
集合是一个
IEnumerable
集合,它包含不同类型的控件,不一定是一个
复选框

您需要强制转换到这些控件的一些常见基本类型(
Control
),然后将集合过滤到
复选框
对象

var query = from Control ctrl in this.Controls
            where ctrl is CheckBox
            select (CheckBox)ctrl; // cast to CheckBox here instead

// which is equivalent to:
var q = this.Controls
            .Cast<Control>()
            .Where(ctrl => ctrl is CheckBox)
            .Select(ctrl => (CheckBox)ctrl);
var query=来自此.Controls中的控件ctrl
其中ctrl是复选框
选中(复选框)ctrl;//改为在此处强制转换为复选框
//这相当于:
var q=此.Controls
.Cast()
。其中(ctrl=>ctrl为复选框)
。选择(ctrl=>(复选框)ctrl);
或者直接使用扩展方法对其进行过滤。结果是一个强类型可枚举
IEnumerable
。我建议采用这种方法

var query = this.Controls.OfType<CheckBox>();
var query=this.Controls.OfType();

是的,我确实使用了您提供的声明,这非常有效。我正在试验我提到的代码,看到错误我感到困惑。感谢您提供的代码片段。第一个建议的修复程序将不起作用。由于基础集合不是强类型,因此必须指定类型。它至少需要:
在这个.Controls中通过对象ctrl键…
@Jeff:你说得对,我忘了
控件
不是通用的。我将删除该位…仅供参考,LINQ to Objects返回
IEnumerable
,而不是
IQueryable
。当我删除ctrl前面的Control关键字时,它显示一个错误“无法解析符号“where”。我使用的是VS.NET 2008,在将对象添加到ctrl前后,我参考了System.Data.Linq AssemblyThank Jeff。基本上,这一切都可以归结为您可以执行
foreach(此.Controls中的字符串s)
foreach(此.Controls中的int I)
等操作的原因(如果您不相信我,请尝试):由于
控件
不是泛型,C#编译器将为您插入一个cast,在运行时执行。犹豫了很久之后,我决定发布我的答案。到目前为止,没有一个答案是完全正确的。这应该是正确的。
var query = this.Controls.OfType<CheckBox>();