我有以下LINQ
语句,其输出必须以另一种方法处理:
var data = from lines in File.ReadAllLines(TrainingDataFile)
.Skip(ContainsHeader ? 1 : 0)
let f = lines.Split(new[] { FieldSeparator }).ToList<String>()
let target = f[TargetVariablePositionZeroBased]
select new { F=f, T=target };
该方法中参数的数据类型应该是什么?
答案 0 :(得分:8)
您无法从方法返回匿名数据类型。您可以从查询中定义一个类并返回该类的对象,并将其传递给target方法。
public class SomeClass
{
public string F {get; set;}
public string T {get; set;}
}
var data = from lines in File.ReadAllLines(TrainingDataFile)
.Skip(ContainsHeader ? 1 : 0)
let f = lines.Split(new[] { FieldSeparator }).ToList<String>()
let target = f[TargetVariablePositionZeroBased]
select new SomeClass { F=f, T=target };
您可以将查询结果IEnumerable<SomeClass>
作为参数传递给方法。
public void MethodToCall(IEnumerable<SomeClass> someClass)
{
}
通过在此示例代码中传递IEnumerable<SomeClass>
中存储的查询结果(data
)来调用方法
MethodToCall(data);
答案 1 :(得分:3)
你不能轻易传递匿名类型。您可以创建一个类,或者由于您的数据只有两个属性,因此请使用Tuple
:
select new Tuple<List<string>, string> (f, target);
如果我的数据类型正确,则参数的数据类型为:
IEnumerable<Tuple<List<string>, string>>
您可以使用F
属性T
和Tuple
来引用Item1
和Item2
。
答案 2 :(得分:3)
1)只是传递查询结果,使你的函数通用,即可:
var data = from lines in File.ReadAllLines(TrainingDataFile)
.Skip(ContainsHeader ? 1 : 0)
let f = lines.Split(new[] { FieldSeparator }).ToList<String>()
let target = f[TargetVariablePositionZeroBased]
select new { F=f, T=target };
SomeMethod(data);
public void SomeMethod<T>(IEnumerable<T> enumerable)
{
// ^^choose the return type..
}
简单。如果方法内部的处理是如此简单,那么这样做。但是,您将无法访问方法内的属性F
和T
。
这样做:
2)您可以使用Eric显示的“{by by example”技巧here。引用他:
我们使用方法类型推断和局部变量类型推断来告诉 编译器“这两个东西是同一类型”。这让你 将匿名类型导出为对象并将其强制转换为匿名类型。
......只有示例和源对象才有效 在同一个程序集中的代码中创建;两个“相同”的匿名类型 在两个不同的程序集中,不统一为同一类型。
SomeMethod(data);
public void SomeMethod(IEnumerable<object> enumerable)
{
var template = new { F = new List<string>(), T = string.Empty };
foreach (var item in enumerable)
{
var anonymousType = item.CastToTypeOf(template);
//print string.Join(", ", anonymousType.F) + " - " + anonymousType.T //compiles
//or whatever
}
}
//a more generic name perhaps is 'CastToTypeOf' as an extension method
public static T CastToTypeOf<T>(this object source, T example) where T : class
{
return (T)source;
}
这里的问题是SomeMethod
现在是为你的匿名类型定制的,因为你在方法中指定了一个特定的类型,所以最好不要使函数通用(尽管你可以这样做)和为该功能提供合适的名称。
3)如果函数现在仅适用于您的独特类型,我最好将它们全部包裹在一个方法中,而不是通过 - 没有麻烦! :)
4)或者您可以委派要对您的匿名类型执行的操作。所以方法签名就像:
SomeMethod(data, d => print string.Join(", ", d.F) + " - " + d.T);
public void SomeMethod<T>(IEnumerable<T> enumerable, Action<T> actor)
{
foreach (var item in enumerable)
actor(item);
}
如果重要,你可以通过再增加一个类型参数来Func
委托。
5)依靠精巧的反思来获取你的匿名类型的属性。
6)在方法参数上使用dynamic
关键字,现在您可以进行动态输入。以上两者都没有给你带来静态输入的好处。
7)你最好拥有一个包含F
和T
的单独课程。这是最好的。 但问问自己,他们是否一起代表某个实体?
8)如果没有,请根据重要内容传递IEnumerable<Tuple>
或IDictionary
。
这完全取决于您希望使用该方法实现的目标。就个人而言,我会在爱好项目中寻找方法2(为了所涉及的乐趣),但在生产代码3,4,7,8中,取决于上下文。