Множество OfType Linq?
У меня есть запрос linq, который выбирает все текстовые поля в заполнителе и добавляет их в список, используя структуру. Мне нужно расширить эту функциональность, чтобы также взять выбранное значение DropDownList. Я уверен, что я делаю это неправильно, потому что когда я отлаживаю метод, количество списков равно 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 />"));
}
}
Ответы
Ответ 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();
Ответ 2
AppDeveloper прав. 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>();
Чтобы узнать больше о методах расширения, см. статью MSDN по этому вопросу.
Обратите внимание, что поскольку метод расширения выше "разрешает" два разных типа, результат по-прежнему является негенерированной последовательностью IEnumerable
. Если вы хотите рассматривать результат как общую последовательность (например, IEnumerable<Control>
), я бы рекомендовал использовать метод расширения Cast<T>
:
var filteredControls = controls.OfType<TextBox, DropDownList>().Cast<Control>();
Ответ 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()));
Смотрите в действии здесь.
Ответ 4
Ваша проблема в OfType<>().OfType<>()
вы дважды фильтруете с разными типами
Ответ 5
Взял @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) });