2013-02-14 1 views
4

RazorEngine.Compile()이 익명 형식을 다른 형식과 다르게 취급하는 것으로 나타났습니다. 예를 들어, 다음 코드를 살펴왜 RazorEngine은 익명 형식의 모델로 템플릿을 동적으로 컴파일합니까?

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는 대신 동적 템플릿을 생성하여 익명 유형에 대한 특별 지원을 제공합니다.

따라서 두 가지 질문이 있습니다. (1)이 동작에 대한 제 이해가 정확합니까? (2) 면도기에 익명 모델의 강력한 형식의 템플릿을 출력하는 방법이 있습니까?

+0

Razor의 작동 방식에 대해 많이 알지 못하는 것 같습니다. 익명의 타입은 실제로 "보통"강한 타입이지만, 템플릿을 컴파일 할 때, 이런 종류의 부두를하기를 원한다고 할지라도 (템플릿이 많은 컨트롤러에서 호출 될 수 있기 때문에) 확실히 사용되는 것을 참조 할 수는 없습니다. – millimoose

+0

그러나 클래스를 생성한다고 가정하면, 동일한 스키마와 한 유형에서 다른 유형으로 맵핑하는 로컬 익명 유형에 대한 코드를 생성 할 수 있습니다. – ChaseMedallion

+0

그들은 모든 일을 할 수 있지만 필요한 노력보다 가치가 중요 할 때 대부분을 펀트하는 것이 더 쉽습니다. 이 경우 강하게 입력하기 위해 코드를 강하게 입력하는 것 외에는 많은 이점이없는 것 같습니다. – millimoose

답변

3

저는 내부 어셈블리를 볼 수 있도록 어셈블리에 a friend assembly을 만들 생각 이었지만 작동하지 않았습니다. 나중에 다음

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

그리고 (TemplateBaseOfT.cs에서) :

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

동일한 파일에 나중에 사용됩니다 면도기 소스 코드에서, 우리는 (CompilerServiceBase.cs)에 다음 코드를 볼 수 있습니다

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

네 - 귀하의 이해가 정확합니다. 또한 Razor는 익명 형식을 동적으로 취급하기 때문에 내부 구조를 표시하는 것으로 충분하지 않음을 알 수 있습니다(). 포함 된 어셈블리의 내부가 보이는 경우 익명 형식을 동적으로 처리하지 않도록 면도기 코드를 패치 할 수 있습니다.

그런 경우에는 모델의 익명 형식과 동일한 속성을 포함하는 새로운 공용 형식을 코드에서 생성해야하므로 Razor에서 생성 된 코드가 해당 형식의 인스턴스를 인스턴스화 할 수 있습니다. 또는 메서드가 익명 형식의 인스턴스를 반환 할 수 있도록 here으로 설명한 해킹을 사용할 수 있습니다.

1

동적 인 경우 에 익명 유형의 경우을 허용합니다. 모델을 컴파일 할 때 어셈블리의 내부에 있기 때문에 익명 형식을 참조 할 수 없습니다. 이를 염두에두고 Razor 파서는 TemplateBase<T>에서 상속받은 템플릿을 생성하여 강력한 형식의 지원을 제공하려고합니다. 따라서을 사용하는 이유는 이러한 속성에 대한 액세스 권한을 DLR에 위임한다는 것을 의미하기 때문입니다.하지만 정적으로 입력 된 클래스의 이점은 상실됩니다.

관련 문제