1

如何在对象内部公开匿名对象dynamic的复杂结构?

匿名对象被标记为internal,所以我正在寻找一种创造性的方法来解决这个问题

// This is the library I control
public void SendObject() {
    var anonymous = new {
        Text = "Test",
        SubItem = new {
            SubText = "Bla",
            SubSub = new {
                SubSubText = "Baha"
            }
        }
    };
}

dynamic dyn = ExposeAnonymous(anonymous); // Perform voodoo

var result = ExternalLibrary.GetSpecialProperty(dyn);

// External library I don't control
public object GetSpecialProperty(dynamic dyn) {
    return dyn.SubItem.SubSub.SubSubText;
}

问题是当发送dynamic我无法控制的其他外部库时,您会收到如下错误:

“object”不包含“SubItem”的定义。

4

3 回答 3

6

问题是在将动态发送到其他库时,

......还有问题。匿名类型internal由 C# 编译器声明为,这意味着其他程序集无权访问它们。

要么停止使用匿名类型,要么使用[InternalsVisibleToAttribute]使该类型对其他程序集可见。在包含创建匿名类型实例的类型的程序集中,使用:

[InternalsVisibleTo("ExternalLibrary")]

(我实际上希望这个问题会出现SubItem而不是SubSub......)

于 2013-04-23T15:35:15.550 回答
5

匿名类型internal和 DLR 在运行时执行与编译器在编译时执行相同的可访问性分析。因此,您不能使用dynamic.

一种选择可能是使用ExpandoObject

        dynamic a = new ExpandoObject();
        a.Text = "Test";
        a.SubItem = new ExpandoObject();
        a.SubItem.SubText = "Blah";
        a.SubItem.SubSub = new ExpandoObject();
        a.SubItem.SubSub.Text = "Baha";

这有点难看,所以您可以保留匿名类型并使用辅助方法递归转换为ExpandoObject

    public static dynamic ConvertToExpando(object obj)
    {
        IDictionary<string, object> expando = new ExpandoObject();
            foreach(var pi in obj.GetType().GetProperties())
            {
                // there doesn't seem to be a way to know if it is an anonymous type directly. So I use IsPublic here.
                if (pi.PropertyType.IsPublic)
                {
                    expando[pi.Name] = pi.GetValue(obj);                    
                }
                else
                {
                    expando[pi.Name] = ConvertToExpando(pi.GetValue(obj));
                }
            }
        return expando;
    }

这会执行您需要的“执行巫术”。

于 2013-04-23T15:54:05.730 回答
1

使用我的开源框架 ImpromptuInterface(在 nuget 中),您可以使用内联语法创建复杂的扩展图。

dynamic New = Builder.New<ExpandoObject>();

dynamic dyn = New.Obj(
        Text: "Test",
        SubItem: New.Obj(
            SubText: "Bla",
            SubSub: New.Obj(
                SubSubText: "Baha"
            )
        )
    );
于 2013-05-02T12:48:26.287 回答