请考虑以下事项:
// select a subset of the DataTable
var subset = DataTable.Where(...).Select(row => new
{
Id = Convert.ToInt32(row["Id"]),
Name = row["Name"].ToString(),
Email = row["Email"].ToString()
});
// or create a new object
var subset = new {
Id = 1,
Name = "something random",
Email = "name@domain.tld"
};
有没有办法将 subset 变量用作方法的参数,而不将其转换为普通Object
?你能以某种方式携带自动生成的变量类型吗?
每次我想将LINQ子集传递给方法时,我都试图避免创建新类。
欢迎使用随机通用方法。
答案 0 :(得分:2)
不,传递匿名类型通常不是一个好主意,因为你丢失了类型信息*。您应该创建一个具体类型并使用它。
var subset = DataTable.Where(...).Select(row => new SomeType
{
Id = Convert.ToInt32(row["Id"]),
Name = row["Name"].ToString(),
Email = row["Email"].ToString()
});
或者,如果您使用的是.NET 4,则可以使用Tuple类型。这是创建“一次性”类型的简单方法,并且仍然可以某些类型安全。
*实际上there is a workaround,但我认为这是一个丑陋的黑客,并建议你不要这样做。
答案 1 :(得分:2)
如果我需要这样做,我使用resharper的“用命名类替换匿名类型”重构选项。然后,您有一个适当的名为类型,以通过API公开,您不必做任何工作。这也为您提供了创建不可变(如匿名类型)或可变,嵌套与顶级等的选项。
顺便说一句,我不建议struct
在这里(来自问题)。
另一种选择是将行为传递给方法 - 即Action<int,string,string> callback
- 然后执行以下操作:
foreach(item in query) callback(item);
但是,我不喜欢这样,因为在以下情况下可能出现错误并不明显:
DoSomething(args, (id, email, name) => Email(To: email, Subject: name));
(错误是它应该可能是(id, name, email)
,如果你明白我的意思了)
答案 2 :(得分:1)
您可以使用通用方法:
public static void Foo<T>(T item)
{
// Do whatever
}
然后,如果你打电话
Foo(subset);
编译器会为您推断T
。是否真的帮助你是另一回事......这取决于方法的意图。显然,Foo
无法引用Id
,Name
,Email
等。
通常,如果多个方法应该知道相同的成员,那么您应该使用命名类型。将它们传递给泛型方法的通常情况是,该方法实际上并不关心涉及的类型,例如在LINQ中。
我已经为C#5发出了一个功能请求,我们应该能够创建具有与匿名类型(不变性,相等性,哈希码生成,ToString
转储)相同功能的类型,但是对于简单命名类型。我们会看看它是否真的发生了......
答案 3 :(得分:0)
匿名类型在创建它们的上下文之外没有提供太多帮助。
如果您需要将匿名类型传递给方法,则此方法非常通用,如(示例)
void PrintAllObjectProperties(object obj);
巫婆你会用反射来做这项工作,或者你做错了什么。
答案 4 :(得分:0)
这就是我想出来的......
对象的扩展方法:
public static class ObjectExtensions
{
/// <summary>
/// Cast Object to anonymous type.
/// E.G.: new Object().ToAnonymousType(new { Property = new Type() });
/// </summary>
public static T ToAnonymousType<T>(this Object o, T t)
{
return (T)o;
}
}
用法:
public void HandleAnonymousTypeAsParameter(Object o)
{
var anonymousType = o.ToAnonymousType(new
{
Id = new Int32(),
Foo = new String(),
Bar = new String()
});
// ... You can do this in even less characters:
var anonymousType = o.ToAnonymousType(new { Id = 0, Foo = "", Bar = "" });
}
HandleAnonymousTypeAsParameter(new
{
Id = 1,
Foo = "foo",
Bar = "bar"
});
积分归John Skeet和Thomas P.