复杂的匿名对象到动态公共属性

Seb*_*son 1 c# dynamic anonymous-types

如何在对象内部公开匿名对象的复杂结构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;
}
Run Code Online (Sandbox Code Playgroud)

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

'object'不包含'SubItem'的定义.

Jon*_*eet 6

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

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

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

[InternalsVisibleTo("ExternalLibrary")]
Run Code Online (Sandbox Code Playgroud)

(我实际上期待这个问题SubItem不是SubSub......)

  • @SebNilsson:是的,为什么你不能添加`InternalsVisibleTo`以便你的类型对RazorEngine可见?事实上,它是*真的*RazorEngine正在使用它,或者它是你正在定义的一些代码,但它被RazorEngine使用*?您应该编辑您的问题以提供更多详细信息. (2认同)

Mik*_*ray 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";
Run Code Online (Sandbox Code Playgroud)

这有点难看,你可以保持匿名类型并使用辅助方法递归转换为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;
    }
Run Code Online (Sandbox Code Playgroud)

这就是你需要的"执行伏都教".