5

RazorEngine.Compile() が匿名型を他の型とは異なる方法で扱っているように見えることに気付きました。たとえば、次のコードを考えてみましょう。

public static void Main()
{
    try {
    var model = new { s = default(string) };
    RazorEngine.Razor.Compile("@Model.s.Length", model.GetType(), "a");
    RazorEngine.Razor.Run(model, "a");
    } catch (Exception ex) {
        Console.WriteLine(ex); // RuntimeBinderException (Cannot perform runtime binding on a null reference)
    }

    try 
    {
    var model = "";
    RazorEngine.Razor.Compile(@"@Model.Length", model.GetType(), "b");
    RazorEngine.Razor.Run(default(string), "b");
    } catch (Exception ex) {
        Console.WriteLine(ex); // NullReferenceException
    }

    try 
    {
    var model = Tuple.Create(default(string));
    RazorEngine.Razor.Compile(@"@Model.Item1.Length", model.GetType(), "c");
    RazorEngine.Razor.Run(model, "c");
    } catch (Exception ex) {
        Console.WriteLine(ex); // NullReferenceException
    }

        try 
    {
    var model = new Internal();
    RazorEngine.Razor.Compile(@"@Model.S.Length", model.GetType(), "d");
    RazorEngine.Razor.Run(model, "d");
    } catch (Exception ex) {
        Console.WriteLine(ex); // TemplateCompilationException (type Internal is not visible)
    }
}

internal class Internal {
    public string S { get; set; }
}

私の理解は次のとおりです。匿名型は内部であるため、通常、Razor はそれらを処理しません。ただし、Razor は代わりに動的テンプレートを生成することにより、匿名型の特別なサポートを提供します。

したがって、2 つの質問があります。(1) この動作に対する私の理解は正しいですか? (2) かみそりに匿名モデルの厳密に型指定されたテンプレートを出力させる方法はありますか?

4

2 に答える 2

3

Razor アセンブリをアセンブリのフレンド アセンブリにする (それによって内部が見えるようにする) というアイデアがありましたが、うまくいきませんでした。Razor ソース コードでは、次のコードを確認できます ( 内CompilerServiceBase.cs)。

 if (modelType != null)
 {
     if (CompilerServices.IsAnonymousType(modelType))
     {
         type.CustomAttributes.Add(new CodeAttributeDeclaration(new CodeTypeReference(typeof(HasDynamicModelAttribute))));
     }
 }

その後(TemplateBaseOfT.cs):

HasDynamicModel = GetType().IsDefined(typeof(HasDynamicModelAttribute), true);

同じファイルで後で使用されます。

if (HasDynamicModel && !(value is DynamicObject) && !(value is ExpandoObject))
    model = new RazorDynamicObject { Model = value };
else
    model = value;

はい、あなたの理解は正しいです。RazorDynamicObjectまた、Razor はすべての匿名型を動的 ( extends )として扱うため、内部を可視化するだけでは不十分であることがわかりますDynamicObject。含まれているアセンブリの内部が表示されている場合、匿名型を動的として扱わないように Razor コードにパッチを当てることができます。

ただし、その場合、Razor によって生成されたコードがその型のインスタンスをインスタンス化できるように、コードはモデルの匿名型と同じプロパティを含む新しいパブリック型を発行する必要があると思います。または、ここで説明されているハックを使用して、メソッドが匿名型のインスタンスを返せるようにすることもできます。

于 2013-02-14T17:04:34.840 に答える
1

動的は、匿名型を許可するために使用されます。モデルをコンパイルするとき、匿名型はアセンブリの内部にあるため参照できません。それを念頭に置いて、Razor パーサーは、TemplateBase<T>厳密に型指定されたサポートを提供するために を継承するテンプレートを生成しようとしています。これが、TemplateBase<dynamic>これらのプロパティへのアクセスを DLR に委譲することを意味するため、使用する理由ですが、静的に型指定されたクラスの利点が失われます。

于 2013-06-26T15:23:39.397 に答える