【问题标题】:Multiple OfType Linq?多个OfType Linq?
【发布时间】:2017-04-03 18:43:17
【问题描述】:

我有一个 linq 查询,它选择占位符中的所有文本框并使用结构将它们添加到列表中。我需要扩展此功能以获取 DropDownList 的 selectedvalue 我很确定我做错了,因为当我调试该方法时,列表计数为 0。

我自己的猜测是声明 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 />"));
    }
}

【问题讨论】:

    标签: c# linq


    【解决方案1】:

    您可以使用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();
    

    【讨论】:

    • 只是代替.OfType&lt;&gt;()?
    • @KasperMackenhauerJacobsen 是的!
    • List&lt;content&gt; rows = PlaceHolder_ForEntries.Controls.Where(c =&gt; c is TextBox || c is DropDownList)替换List&lt;content&gt; rows = PlaceHolder_ForEntries.Controls.OfType&lt;TextBox&gt;().OfType&lt;DropDownList&gt;()
    • 粘贴您的代码时出现此错误:`Compiler Error Message: CS1061: 'System.Web.UI.ControlCollection' does not contain a definition for 'Where' and no extension method 'Where' accepting a first argument of type 'System.Web.UI.ControlCollection' could be found (are you missing a using directive or an assembly reference?)
    • ControlCollection 实现了 IEnumerable,你有 using System.Linq 命名空间吗?
    【解决方案2】:

    AppDeveloper is rightOfType&lt;T&gt; 过滤掉除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&lt;Control&gt;),我建议使用Cast&lt;T&gt; 扩展方法:

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

    【讨论】:

    • 是的,我认为那是我做错了 :) 我不确定如何使用您的解决方案,我将它粘贴到我的课堂上,但我无法像 @987654331 那样使用它@
    • @KasperMackenhauerJacobsen - 您需要在调用该函数之前指定类型!我在丹涛的回答中添加了一个例子!
    • @AppDeveloper 这就是我尝试过的,它给了我这个error: Compiler Error Message: CS1106: Extension method must be defined in a non-generic static class 它只是使用原始OfType 一个重载
    • @KasperMackenhauerJacobsen - 请在您的项目中添加一个额外的静态类any class name 可以。并将代码粘贴到那里。
    • @AppDeveloper 添加新的静态类后,.Select 出现此错误:Compiler Error Message: CS1061: 'System.Collections.IEnumerable' does not contain a definition for 'Select' and no extension method 'Select' accepting a first argument of type 'System.Collections.IEnumerable' could be found (are you missing a using directive or an assembly reference?)
    【解决方案3】:

    我没有彻底阅读这个问题,但从标题的含义来看,您可以通过以下方式实现该行为:

    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

    【讨论】:

      【解决方案4】:

      为扩展方法采用@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) });
      

      【讨论】:

        【解决方案5】:

        您的问题在于OfType&lt;&gt;().OfType&lt;&gt;() 您使用不同类型过滤了两次

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-04-04
          • 1970-01-01
          • 1970-01-01
          • 2018-01-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多