![](/img/trans.png)
[英]Accessing properties of anonymous/dynamic types across dll boundaries gives RuntimeBinderException
[英]RuntimeBinderException when accessing dynamic anonymous type in view
我在学习/修补asp.net时遇到了一个奇怪的异常现象。
我试图显示这样的局部视图:
@Html.Partial("_PartialView", new { Action = "Foo" })
当我尝试访问Action时
// Throws Microsoft.Csharp.RuntimeBinder.RuntimeBinderException
string throwsException = Model.Action;
带有消息的RuntimeBinderExceptionis
'object'不包含'Action'的定义
被扔了。
奇怪的是这条线很好用:
// This line works fine
string works = ((Type)Model.GetType()).GetProperty("Action").GetValue(Model);
这种行为让我很困惑,我宁愿避免使用这种解决方法。 此外,我不认为问题是匿名类型是内部的,因为VS2013中的ASP.NET项目的MVC模板成功完成了此操作:
那么这里发生了什么?
这个问题的答案可以在这里找到: http : //www.heartysoft.com/ashic/blog/2010/5/anonymous-types-c-sharp-4-dynamic
从优秀的博客文章中拉出来:
Anonymous Types are Internal
调用Model.Action
失败的原因是Model
的类型信息在运行时不可用。 它不可用的原因是因为匿名类型不公开。 当该方法返回该匿名类型的实例时,它返回一个System.Object,它引用一个匿名类型的实例 - 一个类型的信息不可用于主程序。 动态运行时尝试在对象上查找名为Action
的属性,但无法从其拥有的类型信息中解析它。 因此,它会引发异常。
那么这里发生了什么?
你的部分视图是弱类型的。 您没有@model
定义。 所以默认情况下它是object
,这显然不具有Action
特性。
解决此问题的正确方法是定义视图模型:
public class MyViewModel
{
public string Action { get; set; }
}
您的部分视图将被强类型化为:
@model MyViewModel
@{
string throwsException = Model.Action;
}
哪个将通过主视图传递:
@Html.Partial("_PartialView", new MyViewModel { Action = "Foo" })
另一种可能性(我个人不喜欢,因为它依赖于运行时绑定)是在局部视图中使用动态模型:
@model dynamic
@{
string throwsException = Model.Action;
}
然后你可以在调用它时传递一个匿名对象:
@Html.Partial("_PartialView", new { Action = "Foo" })
以下是使用反射的一些选项。 在大多数情况下,性能应该可以忽略不计。
实用类
public static class ModelHelper
{
public static T Data<T>( String key)
{
var html = ((System.Web.Mvc.WebViewPage)WebPageContext.Current.Page).Html;
var model = html.ViewData.Model;
return (T)model.GetType().GetProperty(key).GetValue(model) ;
}
}
view.cshtml
@(Html.Partial("partial",new { Id="InstructorId"}))
paritial.cshtml文件
@model dynamic
@{
var id = ModelHelper.Data<String>("Id");
}
在view.cshtml中使用更紧凑的parital调用
@{
var instructorId = "InstructorId";
var windowTitle = "Window Title";
var editorPageUrl = "~/View/Editors/Instructors.chstml";
}
@(Html.Partial("partial",new { instructorId, windowTitle, editorPageUrl }))
将变量调整为在paritial.cshtml文件中获取推断的名称
@model dynamic
@{
var id = ModelHelper.Data<String>("instructorId");
var id = ModelHelper.Data<String>("windowTitle");
var id = ModelHelper.Data<String>("editorPageUrl");
}
创建一个简单的视图模型类并不难,但我不喜欢一次只能用于传递数据的类,所以这对我有用。
您还可以扩展默认视图库
namespace SafetyPlus.Shell.Code
{
public abstract class ExtendedPageBaseClass<TModel> : WebViewPage<TModel> where TModel : class
{
public T Data<T>(String key)
{
return (T)Model.GetType().GetProperty(key).GetValue(Model);
}
public Object Data(String key)
{
return Data<Object>(key);
}
}
}
在/Views/web.config中注册基类
<pages pageBaseType="SafetyPlus.Shell.Code.ExtendedPageBaseClass">
...
</pages>
像这样在部分视图中获取数据
@{
var id = Data("Id");
var idTyped = Data<String>("Id");
}
或者使用我建议的扩展方法。
namespace NotYourDefaultNamespace
{
public static class ModelExtensions
{
public static T Data<T>( this Object model, String key)
{
return (T)model.GetType().GetProperty(key).GetValue(model) ;
}
}
}
这个选项真的不会给你带来什么,因为我们从之前的实用方法中找到了模型。 电话会变成。
@{
var id = Model.Data("Id");
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.