C# 为什么我必须手动创建ExpandooObject才能正确使用dynamic关键字?

C# 为什么我必须手动创建ExpandooObject才能正确使用dynamic关键字?,c#,dynamic,expandoobject,C#,Dynamic,Expandoobject,我在看这个问题。我面临着一个类似的问题: 基本上,我想在ASP.NET MVC中创建一个使用动态参数的“HTML帮助程序”,类似于许多现有帮助程序的htmlArguments参数(下面有更多代码): public BootstrapCell(操作emitContentAction,动态参数) 视图: @使用(grid.Cell(ViewContext.Writer.Write,new{Position=4})) { 僵尸 } 然而,在这种幼稚的方法中,我得到了抛出的RuntimeBinder

我在看这个问题。我面临着一个类似的问题:

基本上,我想在ASP.NET MVC中创建一个使用动态参数的“HTML帮助程序”,类似于许多现有帮助程序的htmlArguments参数(下面有更多代码):

public BootstrapCell(操作emitContentAction,动态参数)
视图:

@使用(grid.Cell(ViewContext.Writer.Write,new{Position=4}))
{
僵尸

}
然而,在这种幼稚的方法中,我得到了抛出的
RuntimeBinderException
,声明
'object'不包含“Position”的定义
,即使在调试和悬停在_args变量上时,它显然有Position属性

调用者和被调用者位于不同的程序集中。为什么会出现这样的问题

(解决方案已在同一个问题中显示:保留args。)

实施:

公共类单元格
{
私有只读字符串\u标记名;
私有动态参数;
私人诉讼;
public BootstrapCell(Action emitContentAction,dynamic args):DisposableBaseClass
{
_args=args;
EmitContentAction=EmitContentAction;
OnContexter();
}
受保护的void onContexter()
{
var sb=新的StringBuilder(“”);
(某人的)行动;
}
}

[经过编辑,以更清楚地说明当“显然”设置Position属性时会出现我的问题。我知道,如果该属性从一开始就没有定义,则必须引发异常。]

该代码存在致命缺陷

只要指定该属性,它就可以工作:

void Bar()
{
    Foo(new {Position = 0});
}

void Foo(dynamic args)
{
    Console.WriteLine(args.Position);
}
这将输出
0
,它不会抛出
RuntimeBinderException

但是这种代码的目的是调用方可以只指定所需的属性,而忽略其余的属性。
您正试图通过
if(args.Position!=null)
检查此遗漏。但这不起作用,它已经需要
位置
存在

当您查看同样支持这些匿名配置对象的ASP.NET路由API时,您会注意到参数的类型是
object
,而不是
dynamic

使用
对象
而不是
动态
将使API能够跨程序集边界使用

那么它是如何工作的呢?

就像在链接答案中一样,您需要手动创建属性字典。您是使用普通的
字典
还是使用
扩展对象
,这取决于您的偏好。
使用
ExpandoObject
将使代码的读写更加简单,但这不是必需的


关于您得到的实际异常:
请注意,它告诉您在
对象
上找不到
位置
属性。如果是缺少
位置
属性的匿名类型,则异常消息不会引用
对象
,而是引用匿名类型。大概是这样的:

“f\uu AnonymousType0”
不包含“位置”的定义


该代码存在致命缺陷

只要指定该属性,它就可以工作:

void Bar()
{
    Foo(new {Position = 0});
}

void Foo(dynamic args)
{
    Console.WriteLine(args.Position);
}
这将输出
0
,它不会抛出
RuntimeBinderException

但是这种代码的目的是调用方可以只指定所需的属性,而忽略其余的属性。
您正试图通过
if(args.Position!=null)
检查此遗漏。但这不起作用,它已经需要
位置
存在

当您查看同样支持这些匿名配置对象的ASP.NET路由API时,您会注意到参数的类型是
object
,而不是
dynamic

使用
对象
而不是
动态
将使API能够跨程序集边界使用

那么它是如何工作的呢?

就像在链接答案中一样,您需要手动创建属性字典。您是使用普通的
字典
还是使用
扩展对象
,这取决于您的偏好。
使用
ExpandoObject
将使代码的读写更加简单,但这不是必需的


关于您得到的实际异常:
请注意,它告诉您在
对象
上找不到
位置
属性。如果是缺少
位置
属性的匿名类型,则异常消息不会引用
对象
,而是引用匿名类型。大概是这样的:

“f\uu AnonymousType0”
不包含“位置”的定义


是的,我知道“position”属性必须存在。如前所述,它“确实存在”,因为在watch窗口中有args.ToString()向我显示“位置=4,大小=6”,但代码仍然抛出异常。@清除屏幕:它不应该这样做,它当然不适合我。请尝试我发布的代码-它会抛出吗?如果没有,试着把它改成你的代码——一次一个修改。我想我就是这么做的,但是我显然不应该在晚上调试。谢谢你在正确的方向推动+1:)@ClearsTheScreen:BTW:您的异常告诉我您在此处显示的代码不是引发异常的代码。调用必须如下所示才能产生异常:
grid.Cell(ViewContext.Writer.Write,new object())
。我这么说是因为异常不会指向
对象
,而是指向一个匿名类型:
'f_uanonymoustype0'不包含“Position”的定义
我的问题很简单,我在ass中使用了
动态
对象