2013-03-16 50 views
12

我有一个linq查询,选择占位符中的所有文本框,并使用结构将它们添加到列表中。我需要扩展此功能,以采取DropDownList的选定值我很确定我做这个错误,因为当我调试方法列表计数为0.多种OfType Linq?

我自己的猜测是,宣布2 OfType<>()是错误的,但我对linq很新,我不知道如何去做。

任何帮助将会很棒!提前致谢。

这是我到目前为止有:

public struct content 
{ 
    public string name; 
    public string memberNo; 
    public int points; 
    public string carclass; 
} 

List<content> rows = new List<content>(); 

protected void LinkButton_Submit_Attendees_Click(object sender, EventArgs e) 
{ 
List<content> rows = PlaceHolder_ForEntries.Controls.OfType<TextBox>().OfType<DropDownList>() 
     .Select(txt => new 
     { 
      Txt = txt, 
      Number = new String(txt.ID.SkipWhile(c => !Char.IsDigit(c)).ToArray()) 
     }) 
     .GroupBy(x => x.Number) 
     .Select(g => new content 
     { 
      carclass = g.First(x => x.Txt.ID.StartsWith("DropDownlist_CarClass")).Txt.SelectedValue, 
      name = g.First(x => x.Txt.ID.StartsWith("TextBox_Name")).Txt.Text, 
      memberNo = g.First(x => x.Txt.ID.StartsWith("TextBox_MemberNo")).Txt.Text, 
      points = int.Parse(g.First(x => x.Txt.ID.StartsWith("TextBox_Points")).Txt.Text) 
     }) 
     .ToList(); 
} 

下面是一个创建控件的方法。

protected void createcontrols() 
{ 
    int count = 0; 
    if (ViewState["count"] != null) 
    { 
     count = (int)ViewState["count"]; 
    } 
    while (PlaceHolder_ForEntries.Controls.Count < count) 
    { 
     TextBox TextBox_Name = new TextBox(); 
     TextBox TextBox_MemberNo = new TextBox(); 
     TextBox TextBox_Points = new TextBox(); 
     DropDownList DropDownList_CarClass = new DropDownList(); 
     DropDownList_CarClass.Items.Add("Car1"); 
     ... 
     DropDownList_CarClass.Items.Add("Car2"); 
     TextBox_Name.Attributes.Add("placeholder", "Navn"); 
     TextBox_Name.ID = "TextBox_Name" + PlaceHolder_ForEntries.Controls.Count.ToString(); 
     TextBox_Name.CssClass = "input-small"; 
     TextBox_MemberNo.Attributes.Add("placeholder", "Medlemsnr."); 
     TextBox_MemberNo.ID = "TextBox_MemberNo" + PlaceHolder_ForEntries.Controls.Count.ToString(); 
     TextBox_MemberNo.CssClass = "input-small"; 
     TextBox_Points.Attributes.Add("placeholder", "Point"); 
     TextBox_Points.ID = "TextBox_Points" + PlaceHolder_ForEntries.Controls.Count.ToString(); 
     TextBox_Points.CssClass = "input-small"; 
     PlaceHolder_ForEntries.Controls.Add(TextBox_Name); 
     PlaceHolder_ForEntries.Controls.Add(TextBox_MemberNo); 
     PlaceHolder_ForEntries.Controls.Add(DropDownList_CarClass); 
     PlaceHolder_ForEntries.Controls.Add(TextBox_Points); 
     PlaceHolder_ForEntries.Controls.Add(new LiteralControl("<br />")); 
    } 
} 

回答

16

可以使用Where和检查类型的对象is的实例!

List<content> rows = PlaceHolder_ForEntries.Controls.Cast<Control>().Where(c => c is TextBox || c is DropDownList) 
     .Select(txt => new 
     { 
      Txt = txt, 
      Number = new String(txt.ID.SkipWhile(c => !Char.IsDigit(c)).ToArray()) 
     }) 
     .GroupBy(x => x.Number) 
     .Select(g => new content 
     { 
      carclass = g.First(x => x.Txt.ID.StartsWith("DropDownlist_CarClass")).Txt.SelectedValue, 
      name = g.First(x => x.Txt.ID.StartsWith("TextBox_Name")).Txt.Text, 
      memberNo = g.First(x => x.Txt.ID.StartsWith("TextBox_MemberNo")).Txt.Text, 
      points = int.Parse(g.First(x => x.Txt.ID.StartsWith("TextBox_Points")).Txt.Text) 
     }) 
     .ToList(); 
+0

的只是代替'.OfType <>()'? – mackwerk 2013-03-16 17:13:39

+0

@KasperMackenhauerJacobsen是的! – 2013-03-16 17:14:51

+1

替换'List rows = PlaceHolder_ForEntries.Controls.OfType ()。OfType ()'with'List rows = PlaceHolder_ForEntries.Controls.Where(c => c是TextBox || c是DropDownList)' – 2013-03-16 17:15:16

0

你的问题是在OfType<>().OfType<>()你与不同类型的

9

AppDeveloper is right过滤两次。 OfType<T>过滤除T以外的所有类型的对象;所以通过过滤两次,可以有效地消除列表中的所有对象。

如果你想换这个逻辑(过滤所有,但类型从列表)弄成可重复使用的,什么也没有阻止你实现自己的扩展方法:

using System.Collections; 

public static class EnumerableExtensions 
{ 
    public static IEnumerable OfType<T1, T2>(this IEnumerable source) 
    { 
     foreach (object item in source) 
     { 
      if (item is T1 || item is T2) 
      { 
       yield return item; 
      } 
     } 
    } 
} 

包含上述类的项目将允许你写这样的代码在你的应用程序:

var textBoxesAndDropDowns = controls.OfType<TextBox, DropDownList>(); 

要了解更多关于扩展方法,请参阅the MSDN article on the subject

请注意,由于上面的“允许”两种不同类型的扩展方法,结果仍然是一个非泛型的IEnumerable序列。如果你想结果视为一个通用序列(例如,IEnumerable<Control>),我会建议使用Cast<T>扩展方法:

var filteredControls = controls.OfType<TextBox, DropDownList>().Cast<Control>(); 
+0

是的,我认为这就是我做错了:) 虽然我不确定如何使用你的解决方案,但我不能像'.OfType <>()一样使用它“ – mackwerk 2013-03-16 17:33:44

+0

@KasperMackenhauerJacobsen - 你需要在调用该函数之前指定类型!我为丹涛的回答增加了一个例子! – 2013-03-16 18:02:48

+0

@AppDeveloper这就是我所尝试的,它给了我这个错误:编译器错误消息:CS1106:扩展方法必须在非泛型静态类中定义它只使用原始的'OfType'和一个过载 – mackwerk 2013-03-16 18:05:24

1

我还没有仔细阅读的问题,但是从标题意味着什么,你可以实现以下行为:

var collection = new object[] { 5, "4545", 'd', 54.5 , 576 }; 

var allowedTypes = new[] { typeof(string), typeof(int) }; 
var result = collection 
.Where(item => allowedTypes.Contains(item.GetType())); 

看到它的行动here

0

注意到@Shimmys答案为扩展方法:

/// <param name="wantedTypes">--- Sample: --- new Type[] { typeof(Label), typeof(Button) }</param> 
public static IEnumerable OfTypes(this IEnumerable collection, Type[] wantedTypes) 
{ 
    if (wantedTypes == null) 
     return null; 
    else 
     return collection.Cast<object>().Where(element => wantedTypes.Contains(element.GetType())); 
} 

用法:

// List of 3 different controls 
List<object> controls = new List<object>(new object[] { new Label(), new Button(), new TextBox() }); 

// Get all labels and buttons 
var labelsAndButtons = controls.OfTypes(new Type[] { typeof(Label), typeof(Button) });