传递匿名类型作为参数给函数

4

我需要将一个匿名类型的对象传递给一个函数。

我期望这个对象包含一些属性,比如说Name(字符串)和Rang(BO)。

举个例子,我有一个查询:

  Dim query = From city In _container.Cities
               From street In city.Streets
               Select Name = street.Name, Rang = street.Rang
               Distinct

现在,我想将这个查询的每个元素传递给一个函数。
这可行吗?

你不想使用名义类型有特别的原因吗?这会使事情变得更加容易,也更加清晰。 - dlev
@dlev:我有很多像这样的查询,我应该为每个查询构建一个对象吗? - serhio
1
这取决于你的模型,但更常见的情况是为每个实体使用名义类型,并将它们传递。由于您正在使用VB,JaredPar的答案也应该可以。 - dlev
5个回答

4

是的,这是可能的。

你可以使用示例进行转换。这里是一个示例:

class CastByExample {
    public T Cast<T>(T t, object toCast) {
        return (T)toCast;
    }

    public void M(object o) {
        var y = Cast(new { Name = "Name", Range = 0 }, o);
        Console.WriteLine(y.Name);
    }

    public void Test() {
        var x = new { Name = "John Doe", Range = 17 };
        M(x);
    }
}

您也可以使用反射。

但实际上,通过这些步骤跳跃比编写具体的非匿名类型更容易吗?


你希望转换成什么类型? - Reed Copsey
1
@JaredPar:这是一个可以接受的C#答案,问题并不特定于VB.NET。 - serhio
@JaredPar:这个标签是.NET,不是VB.NET。 - jason
这个例子有一些严重的缺陷 - 在最简单的情况下它可以工作。然而,如果您稍后进行重构并将一个方法移动到另一个库中,例如,强制转换将会失败... 这真的不是一个解决方案,而是一种可怕的黑客方式,以一种从未打算使用的方式绕过这个问题... - Reed Copsey
@Reed Copsey: “但是,实际上,跳跃这些障碍比编写具体的非匿名类型更容易吗?” - jason
显示剩余6条评论

3
总之,不行。来自MSDN的说法:
“您不能将字段、属性、事件或方法的返回类型声明为匿名类型。同样,您也不能将方法、属性、构造函数或索引器的形式参数声明为匿名类型。” http://msdn.microsoft.com/en-us/library/bb397696.aspx 没有一种好的方法(意思是简单的)可以在方法之间传递匿名类型。我会创建一个辅助类代替。
话虽如此,你可能还会对Jon Skeet关于匿名类型离开方法范围的文章感兴趣:

http://blogs.msmvps.com/jonskeet/2009/01/09/horrible-grotty-hack-returning-an-anonymous-type-instance/


@serhio:唯一重要的是你有多少个函数 - 而不是有多少个查询... - Reed Copsey
@Reed Copsey 好的,我有很多函数,现在,我应该为每个函数构建一个对象吗? - serhio
@serhio:个人而言,我会为域中的每个业务对象构建一个对象,以便您传递有意义的内容。您应该能够在函数中重用类型(或者在类型本身上定义函数,这甚至更好...) - Reed Copsey
是的,从Jon Skeet的文章中我看到了Jason的回答。 - serhio
Jon Skeet 文章中的链接已失效。 - mbomb007

3

在VB.Net中,无法确定匿名对象的类型。但是,如果您熟悉Option Strict Off,那么可以使用后期绑定。只需要使目标方法接受Object类型的参数即可。

Public Sub UseAnonymousObject(ByVal p as Object)
  Console.WriteLine(p.Name)
  Console.WriteLine(p.Rang)
End Sub

...

For Each current in query 
  UseAnonymousObject(current)
Next

如果我不喜欢关闭Option Strict选项怎么办? - serhio
如果没有使用Option Strict Off,那么你需要进行强制转换或者最好定义一个包含所需属性的简单类型,并使用该类型。 - JaredPar
在我的情况下,“定义一个简单类型”变成了“定义一些示例类型”(很多)。 - serhio

1

我没有深入研究过它们,也许我没有理解你的问题,但如果你使用 .Net 4 框架,你可以使用 Tuples 而不是匿名类型。它们似乎失去了匿名类型中很好的显式属性命名,但它们有一个优点,就是它们可以在方法之间传递。

然而,另一个缺点是方法签名仍然需要用正确的 Tuple 定义来定义。因此,在大多数情况下,我不确定它是否比使用非匿名类型更有优势,因为它在灵活性方面提供的东西,在有意义的参数通信方面却受到阻碍。

因此,我不建议在任何广泛的接口层面上使用它们(例如,具有像 Tuple 这样的参数类型的公开暴露方法,更适合于明确定义的类型定义,而不是过于模糊的 Tuple 参数)。它们可能很方便,也很适合支持一次性、临时的类型对象的私有方法。


0

我没有尝试过,但使用动态如何?

IEnumerable<dynamic> SubMethod(...)
{
    ....
    return (IEnumerable<dynamic>) (from .... select new{Property1 = v1,...})
}

void Method()
{
    var q = SubMethod().FirstOrDefault();  //or whatever
    var j = q.Property1;
    ...
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接