C# 将IEnumerable数据作为参数从LINQ传递给方法

C# 将IEnumerable数据作为参数从LINQ传递给方法,c#,linq,C#,Linq,可能重复: 我有以下LINQ语句,其输出必须用另一种方法处理: var data = from lines in File.ReadAllLines(TrainingDataFile) .Skip(ContainsHeader ? 1 : 0) let f = lines.Split(new[] { FieldSeparator }).ToList<String>() let ta

可能重复:

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

将获取此数据的方法中参数的数据类型应该是什么?

您不能从方法返回匿名数据类型。您可以定义一个类并从查询返回该类的对象,然后将其传递给目标方法

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<Tuple<List<string>, string>>

您可以使用元组属性Item1和Item2引用F和T。

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..
}
这里需要注意的是,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依赖fiddly反射从匿名类型获取属性,否则

6在方法参数上使用dynamic关键字,现在就有了动态类型。以上两种方法都没有给你静态类型的好处

7你最好有一个单独的班级来容纳F和T,这是最好的。但是问问你自己,它们一起代表了一个实体吗

8如果没有,只需根据重要内容传递IEnumerable或IDictionary


这完全取决于你想用这种方法实现什么/如何实现。就我个人而言,我会在一个爱好项目中选择方法2以获得乐趣,但在生产代码3、4、7、8中,这取决于上下文。

您不能从方法返回匿名数据类型。-没错,但问题不是这样问的。问题要求将匿名数据类型传递给方法。当方法是泛型方法时,这是可能的。一个泛型方法在这里是否有用取决于该方法应该做什么。显然,IEnumerable不能接受两个参数…它是一个泛型类1 1参数..所以这不起作用它只有一个参数:Tuple。你试过了吗?那很聪明:……会试的that@Aadith对于类似的例子,考虑标准类型字典,它实现iQueDaby。这是完全正确的:IEnumerable有一个泛型类型参数,即KeyValuePair.or dynamic,也可以使用它。@Yossarian true,但我鄙视它:
IEnumerable<Tuple<List<string>, string>>
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..
}
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(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);
}