【茶包射手日記】CSHTML ViewBag無法使用擴充方法

在ASP.NET MVC裡定義了一個擴充方法(Extension Method),打算在CSHTML中使用:(以下擴充方法為脫褲子放屁,純屬示範,為String新増一個GetLength()方法傳回字串長度)

namespace BBDPWeb.Models
{
    public static class ExtMethodDemo
    {
        public static int GetLength(this string s)
        {
            return s.Length;
        }
    }
}

在Action中,使用Title存入標題字串放入ViewBag,在CSHTML則加入using BBDPWeb.Models,確保引用ExtMethoDemo所在命名空間啟用擴充方法,既然Title為String,理論上ViewBag.Title.GetLength()應可取得字串長度。

@using BBDPWeb.Models
 
<!DOCTYPE html>
<html ng-app="app">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>@ViewBag.Title.GetLength() - BBDP</title>
    @Styles.Render("~/Content/css")
    @Scripts.Render("~/bundles/modernizr")
    <link href="~/Content/kendo/kendo.common.min.css" rel="stylesheet" />
    <link href="~/Content/kendo/kendo.afet.min.css" rel="stylesheet" />

錯!CSHTML彈出錯誤訊息,指出Title沒有GetLength()這個方法。

一開始猛往「沒正確引用命名空間」方向追查,繞了半圈才發現問題出在ViewBag上。

ViewBag的型別為dynamic,故編譯階段難以判別ViewBag.Title型別為何,無法確認其為String就不會套用String專屬的擴充方法。

stackoverflow查到一段說明:(原PO曾為微軟RD)

In regular, non-dynamic code extension methods work by doing a full search of all the classes known to the compiler for a static class that has an extension method that match. The search goes in order based on the namespace nesting and available "using" directives in each namespace.

That means that in order to get a dynamic extension method invocation resolved correctly, somehow the DLR has to know at runtime what all the namespace nestings and "using" directives were in your source code. We do not have a mechanism handy for encoding all that information into the call site. We considered inventing such a mechanism, but decided that it was too high cost and produced too much schedule risk to be worth it.

簡單地說,動態型別要使用擴充函式,必須在執行期間搜索所有關聯的命名空間,難度極高,故.NET Team未將其納入內建功能。要在動態物件(不限於MVC CSHTML,任何用到dynamic的地方都是如此)使用擴充函式,必須加上強型別宣告。

知道原委,將程式修改為((string)ViewBag.Title).GetLength(),就能正確呼叫擴充方法囉~

@using BBDPWeb.Models
 
<!DOCTYPE html>
<html ng-app="app">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>@(((string)ViewBag.Title).GetLength()) - BBDP</title>
    @Styles.Render("~/Content/css")
    @Scripts.Render("~/bundles/modernizr")
    <link href="~/Content/kendo/kendo.common.min.css" rel="stylesheet" />
    <link href="~/Content/kendo/kendo.afet.min.css" rel="stylesheet" />
 
歡迎推文分享:
Published 01 October 2015 08:02 AM 由 Jeffrey
Filed under: ,
Views: 3,615



意見

沒有意見

你的看法呢?

(必要的) 
(必要的) 
(選擇性的)
(必要的) 
(提醒: 因快取機制,您的留言幾分鐘後才會顯示在網站,請耐心稍候)

5 + 3 =

搜尋

Go

<October 2015>
SunMonTueWedThuFriSat
27282930123
45678910
11121314151617
18192021222324
25262728293031
1234567
 
RSS
創用 CC 授權條款
【廣告】
twMVC

Tags 分類檢視
關於作者

一個醉心技術又酷愛分享的Coding魔人,十年的IT職場生涯,寫過系統、管過專案, 也帶過團隊,最後還是無怨無悔地選擇了技術鑽研這條路,近年來則以做一個"有為的中年人"自許。

文章典藏
其他功能

這個部落格


Syndication