meh*_*nik 85 dynamic anonymous-types c#-4.0
只要我在班级和班级ClassSameAssembly相同的班级中,下面的代码就能正常运行Program.但是当我将类移动ClassSameAssembly到一个单独的程序集时,RuntimeBinderException会抛出一个(见下文).有可能解决它吗?
using System;
namespace ConsoleApplication2
{
public static class ClassSameAssembly
{
public static dynamic GetValues()
{
return new
{
Name = "Michael", Age = 20
};
}
}
internal class Program
{
private static void Main(string[] args)
{
var d = ClassSameAssembly.GetValues();
Console.WriteLine("{0} is {1} years old", d.Name, d.Age);
}
}
}
Run Code Online (Sandbox Code Playgroud)
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException:'object'不包含'Name'的定义
at CallSite.Target(Closure , CallSite , Object )
at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0)
at ConsoleApplication2.Program.Main(String[] args) in C:\temp\Projects\ConsoleApplication2\ConsoleApplication2\Program.cs:line 23
Run Code Online (Sandbox Code Playgroud)
Jon*_*eet 113
我认为问题是匿名类型是生成的internal,因此绑定器并不真正"知道"它本身.
请尝试使用ExpandoObject:
public static dynamic GetValues()
{
dynamic expando = new ExpandoObject();
expando.Name = "Michael";
expando.Age = 20;
return expando;
}
Run Code Online (Sandbox Code Playgroud)
我知道这有点难看,但这是我现在能想到的最好的...我不认为你甚至可以使用它的对象初始化器,因为它是强类型的,因为ExpandoObject编译器不知道该怎么做用"名字"和"年龄".你可以这样做:
dynamic expando = new ExpandoObject()
{
{ "Name", "Michael" },
{ "Age", 20 }
};
return expando;
Run Code Online (Sandbox Code Playgroud)
但那不是更好......
你可以潜在地写一个扩展方法匿名类型转换为在Expando通过反射相同的内容.然后你可以写:
return new { Name = "Michael", Age = 20 }.ToExpando();
Run Code Online (Sandbox Code Playgroud)
虽然这很可怕:(
ema*_*ema 61
您可以使用它[assembly: InternalsVisibleTo("YourAssemblyName")]来使装配体内部可见.
Vic*_*tor 10
我遇到了类似问题,并希望在Jon Skeets的答案中添加另一种选择.我发现的原因是我意识到Asp MVC3中的许多扩展方法使用匿名类作为输入来提供html属性(new {alt ="Image alt",style ="padding-top:5px"} =>
无论如何 - 这些函数使用RouteValueDictionary类的构造函数.我自己试过,确定它有效 - 虽然只有第一级(我使用了多级结构).所以 - 在代码中这将是:
object o = new {
name = "theName",
props = new {
p1 = "prop1",
p2 = "prop2"
}
}
SeparateAssembly.TextFunc(o)
//In SeparateAssembly:
public void TextFunc(Object o) {
var rvd = new RouteValueDictionary(o);
//Does not work:
Console.WriteLine(o.name);
Console.WriteLine(o.props.p1);
//DOES work!
Console.WriteLine(rvd["name"]);
//Does not work
Console.WriteLine(rvd["props"].p1);
Console.WriteLine(rvd["props"]["p1"]);
Run Code Online (Sandbox Code Playgroud)
所以...这里到底发生了什么?在RouteValueDictionary中查看此代码(上面的值〜= o):
foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(values))
object obj2 = descriptor.GetValue(values);
//"this.Add" would of course need to be adapted
this.Add(descriptor.Name, obj2);
}
Run Code Online (Sandbox Code Playgroud)
所以 - 使用TypeDescriptor.GetProperties(o)我们将能够获得属性和值,尽管匿名类型在单独的程序集中被构造为内部!当然,这很容易扩展以使其递归.并根据需要制作扩展方法.
希望这可以帮助!
/胜利者