![](/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.