【问题标题】:Passing IEnumerable data from LINQ as parameter to a method [duplicate]将 IEnumerable 数据从 LINQ 作为参数传递给方法 [重复]
【发布时间】:2013-01-03 03:59:04
【问题描述】:

可能重复:
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 };

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

【问题讨论】:

    标签: c# linq


    【解决方案1】:

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

    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&lt;SomeClass&gt;作为参数传递给方法。

    public void MethodToCall(IEnumerable<SomeClass> someClass)
    {
    
    }
    

    通过传递此示例代码中存储在data 中的查询结果(IEnumerable&lt;SomeClass&gt;)来调用方法

    MethodToCall(data);
    

    【讨论】:

    • "您不能从方法中返回匿名数据类型。" ——没错,但这不是问题要问的。问题要求将匿名数据类型传递 一个方法。当方法是通用方法时,这是可能的。 (泛型方法在这里是否有用取决于该方法应该做什么。)
    【解决方案2】:

    你不能很容易地传递匿名类型。您可以创建一个类,或者由于您的数据只有两个属性,请使用Tuple

    select new Tuple<List<string>, string> (f, target);
    

    如果我的数据类型正确,那么参数的数据类型将是:

    IEnumerable<Tuple<List<string>, string>>
    

    您将使用Tuple 属性Item1Item2 引用FT

    【讨论】:

    • 显然,IEnumerable 不能接受两个参数...它是一个通用类 1 参数..所以这不起作用
    • 它只有一个参数:Tuple&lt;List&lt;string&gt;, string&gt;。你试过了吗?
    • 这很聪明:) ..会试试的
    • @Aadith 类似的例子,考虑标准类型Dictionary&lt;TKey, TValue&gt;,它实现了IEnumerable&lt;KeyValuePair&lt;TKey, TValue&gt;&gt;。这是完全有效的:IEnumerable 有一个泛型类型参数,即KeyValuePair&lt;TKey, TValue&gt;
    【解决方案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 的 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&lt;Tuple&gt;IDictionary,具体取决于重要事项。


    这完全取决于您想用该方法实现什么/如何实现。就个人而言,我会在一个爱好项目中选择方法 2(为了其中的乐趣),但在生产代码 3、4、7、8 中取决于上下文。

    【讨论】:

    • dynamic,也可以。
    • @Yossarian 没错,但我鄙视它:)
    猜你喜欢
    • 2013-04-09
    • 1970-01-01
    • 1970-01-01
    • 2011-04-30
    • 2013-07-01
    • 1970-01-01
    • 2011-07-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多