8

可能重复:
如何将匿名类型传递给方法?

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

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

4

3 回答 3

8

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

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);
于 2013-01-19T15:38:49.633 回答
3

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

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

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

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

并且您将引用FT使用Tuple属性Item1Item2.

于 2013-01-19T15:40:05.550 回答
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此处显示的“示例转换”技巧。引用他的话:

我们使用方法类型推断和局部变量类型推断来告诉编译器“这两个东西是同一类型”。这使您可以将匿名类型导出为对象并将其转换回匿名类型。

...该技巧仅在示例和源对象是在同一程序集中的代码中创建时才有效;两个不同程序集中的两个“相同”匿名类型不会统一为同一类型。

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

于 2013-01-19T15:46:26.623 回答