【问题标题】:Return/consume dynamic anonymous type across assembly boundaries跨程序集边界返回/使用动态匿名类型
【发布时间】:2011-02-28 21:48:48
【问题描述】:

下面的代码效果很好。如果 GetUse 方法位于不同的程序集中,则代码将失败并出现 RuntimeBinderException。这是因为 .Net 运行时系统仅保证程序集中的匿名类型(在本例中为 <string, int>)的通用性。

有没有办法欺骗运行时系统来克服这个问题?我可以在Use端的调试器中检查对象,调试器可以看到相关属性。

class Program
{
    static void Main(string[] args)
    {
        UsePerson();
        Console.ReadLine();
    }

    public static void UsePerson()
    {
        var person = GetPerson();

        Console.WriteLine(person.Name);
    }

    public static dynamic GetPerson()
    {
        return new { Name = "Foo", Age = 30 };
    }
}

【问题讨论】:

    标签: c# .net dynamic anonymous-types


    【解决方案1】:

    使用ExpandoObject 而不是匿名类型。这应该可以让您安全地跨越装配边界:

    public static dynamic GetPerson()
    {
        dynamic person = new ExpandoObject();
        person.Name = "Foo";
        person.Age = 30;
    
        return person;
    }
    

    一般来说,匿名类型实际上应该只在生成它们的方法中使用。从方法返回匿名类型通常会导致比它解决的问题更多的问题。

    【讨论】:

    • 最佳答案,因为 ExpandoObject 解决了交叉装配限制。
    【解决方案2】:

    问题的原因是匿名类型是程序集内部的。这就是动态语言运行时不允许您访问另一个程序集的属性的原因。

    post 解释了一个解决方案。您可以在程序集中放置一个自定义属性,该属性定义了允许其他程序集访问其内部的匿名类型。

    另一个解决方案是返回一个公共类的对象(具有公共属性)。当然,这会扼杀匿名类型的优势。

    按照 Reed Copsey 的建议,第三种解决方案是使用 ExpandoObject

    如果您仍想使用匿名类型,您可以编写一个动态类来“装饰”任何匿名类型并公开其成员。这样的类必须实现IDynamicMetaObjectProvider 接口并通过反射访问装饰对象。可能,这些东西已经被某个人实现了。

    【讨论】:

    • 上述帖子中的解决方案“1”实际上非常有趣。基本上,您的 assemblyinfo.cs 中的 [assembly: InternalsVisibleTo("SomeOtherAssembly")] 效果很好。
    【解决方案3】:

    另一个好的解决方案可能是使用 .Net 4 中引入的元组:http://msdn.microsoft.com/en-us/library/dd268536.aspx

    【讨论】:

      【解决方案4】:

      即兴界面

      http://code.google.com/p/impromptu-interface/

      将允许您跨边界使用匿名类型实例,但您必须声明一个与它的签名匹配的接口,或者至少是您希望从它的签名中访问的接口。

      【讨论】:

        【解决方案5】:

        这是一个穷人的解决方法; Newtonsoft.Json 来救援,因为序列化往返会生成对您/正在工作的程序集可见的动态类型实例。

        public static class TypeExt
        {
          // roundtrip json serialization to enable access to dynamic members and properties originating from another assembly
          public static T JClone<T>( this T source ) { return JsonConvert.DeserializeObject<T>( JsonConvert.SerializeObject( source ) ); }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-04-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-09-28
          相关资源
          最近更新 更多