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 的 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 中取决于上下文。