将LINQ中的IEnumerable数据作为参数传递给方法

时间:2013-01-19 15:37:16

标签: c# linq

  

可能重复:
  How can I pass an anonymous type to a method?

我有以下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 };

该方法中参数的数据类型应该是什么?

3 个答案:

答案 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属性TTuple来引用Item1Item2

答案 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..
}

简单。如果方法内部的处理是如此简单,那么这样做。但是,您将无法访问方法内的属性FT

这样做:

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)你最好拥有一个包含FT的单独课程。这是最好的。 但问问自己,他们是否一起代表某个实体

8)如果没有,请根据重要内容传递IEnumerable<Tuple>IDictionary


这完全取决于您希望使用该方法实现的目标。就个人而言,我会在爱好项目中寻找方法2(为了所涉及的乐趣),但在生产代码3,4,7,8中,取决于上下文。