我有一个
List<object> list = new List<object>();
while (myReader.Read())
{
string arrKablan = myReader["arrK_Title"].ToString();
string arrTotal = myReader["arrTotal"].ToString();
string _title = myReader["MF_Title"].ToString();
string _path = myReader["MF_Path"].ToString();
int _level = Convert.ToInt32(myReader["MF_Level"].ToString());
list.Add(new { title = _title, path = _path, kablanim = arrKablan, total = arrTotal, level = _level });
}
我只需要选择level == 1
的项目我试过
list = list.where(item => item.level == 1);
但我收到错误
'object' does not contain a definition for 'level' and no extension method 'level' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?)
我知道编译器可以获得类型,这样他就可以知道它是什么&#34; level&#34;。 如何在不定义类的情况下实现这种选择?
答案 0 :(得分:4)
您有两种解决方法:
使用List<dynamic>
代替List<object>
。这将禁用类型检查。缺点:这将禁用类型检查。 : - )
让编译器推断出列表的正确类型。为此,请让您的数据层返回DataTable
而不是DataReader
,然后使用LINQ创建列表:
var myList = (from drow in myDataTable.AsEnumerable()
select new {
kablanim = drow["arrK_Title"].ToString(),
total = drow["arrTotal"].ToString(),
...
}).ToList();
答案 1 :(得分:2)
我不明白你为什么不做一个具体的课程:
public class Foo
{
public string Title { get; set; }
public string Path { get; set; }
// etc, etc
}
然后
List<Foo> list = new List<Foo>();
while (myReader.Read())
{
string arrKablan = myReader["arrK_Title"].ToString();
string arrTotal = myReader["arrTotal"].ToString();
string _title = myReader["MF_Title"].ToString();
string _path = myReader["MF_Path"].ToString();
int _level = Convert.ToInt32(myReader["MF_Level"].ToString());
list.Add(new Foo { Title = _title, Path = _path, /* etc, etc */ });
}
然后你打电话给
list = list.Where(item => item.Level == 1).ToList();
(请注意使ToList
分配有效所需的额外list
次呼叫
答案 2 :(得分:2)
为了完整起见,您也可以这样做。创建一个函数,使用反射从任何对象获取值:
private T GetValue<T>(object obj, string property)
{
return (T)obj.GetType()
.GetProperties()
.Single(p => p.Name == property)
.GetValue(obj);
}
并称之为:
var filteredList = list.Where(item => GetValue<int>(item, "level") == 1);
答案 3 :(得分:1)
您可以在匿名类中获取属性的值,如下所示:
var anon = new { Level = "level", Time = DateTime.Now };
Type type = anon.GetType();
var props = type.GetProperties();
foreach (var propertyInfo in props)
{
if (propertyInfo.Name == "Level")
{
var x =propertyInfo.GetValue(anon);
}
}
我不确定这是否是实现这一目标的最佳途径,但肯定是可能的。
答案 4 :(得分:0)
您正在将匿名类的对象添加到列表中。您可以仅在您已定义的方法中引用此匿名类字段,并且您应该避免将其添加到列表中,因为现在还有其他方式可以反射或动态访问该对象的字段。< / p>
例如,您可以访问以下元素之一: var list = new List();
list.Add(new { field1 = "a", field2 = 2 });
list.Add(new { field1 = "b", field2 = 3 });
list.Add(new { field1 = "c", field2 = 4 });
dynamic o = list[1];
Console.WriteLine(o.field1);
Console.WriteLine(o.field2);
但是你应该知道,这个动态功能对每个成员访问都有很大的开销。
如果你真的想使用lambdas,你可以重写
list = list.where(item => item.level == 1);
像这样
var filtered = list.Where(item =>
{
dynamic ditem = item;
return ditem.Level == 1;
});
但这是一个糟糕的方法。
另一种方法是使用反射并像这样重写这个lambda
var filtered = list.Where(item =>
{
var field = item.GetType().GetField("level");
return (int)field.GetValue(item) == 1;
});
这比使用动态更好,因为它的开销较小,但仍然非常昂贵。
如果您的匿名对象具有相同的类型,那么在循环外缓存FieldInfo对象可能会更好。它可以这样做
var field = list.First().GetType().GetField("level");
var filtered = list.Where(item => (int)field.GetValue(item) == 1);
答案 5 :(得分:0)
出于性能原因,Linq依赖于在编译时可用的元数据。通过明确声明List<object>
,您已将此列表的元素键入为object
,但没有成员level
。
如果你想像这样使用Linq,你有两个选择。
选项1是首选方法。通常,Linq与数据库一起使用,并且Visual Studio直接从数据库生成类。这就是为什么没有人抱怨类需要提供元数据的原因。
答案 6 :(得分:-1)
以下行创建匿名类。
new { title = _title, path = _path, kablanim = arrKablan, total = arrTotal, level = _level });
你无法将你的对象强制转换为有意义的东西。 对象没有这些属性。 您必须自己创建一个类并使用它。