2017-12-02 22 views
0

익명 호출자가 포함될 수있는 호출자 제공 객체에 임의 필드를 설정할 수있는 코드를 작성하려고합니다. 델리게이트 생성은 불가능합니다 (Expression 컴파일러는 익명 객체의 필드가 읽기 전용이라는 것을 인식합니다). 그래서 IL을 일부 방출했습니다. 그러나이 작업을 수행 할 때 VerificationException ("작업으로 인해 런타임이 불안정해질 수 있음)이 실행 중입니다. 동일한 간단한 코드가 일반 필드가있는 객체에서 잘 실행됩니다. 읽기 전용 필드에서 실패합니다. 그 밖의 무엇을 여기서 할 수 있습니까? .Net 4.6.2를 실행 중입니다.읽기 전용 필드 (C#)를 설정할 때의 VerificationException

미리 감사드립니다.

class TestRegular 
{ 
    private string field; 
} 

class TestReadOnly 
{ 
    private readonly string field; 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     Verify(new TestRegular());  // this works 
     Verify(new TestReadOnly()); // this does not work 
     Verify(new { field = "abc" }); // this does not work 
     Console.WriteLine("Done"); 
    } 

    private static void Verify<T>(T test) 
    { 
     var fields = typeof(T).GetFields(BindingFlags.Instance | BindingFlags.NonPublic); 
     Action <T, object> setter = CompileSetter<T>(fields[0]); 
     setter(test, "value"); 
    } 

    private static Action<TResult, object> CompileSetter<TResult>(FieldInfo field) 
    { 
     string methodName = field.ReflectedType.FullName + ".TestSetter"; 
     DynamicMethod setterMethod = new DynamicMethod(methodName, null, new[] { typeof(TResult), typeof(object) }, true); 
     ILGenerator gen = setterMethod.GetILGenerator(); 

     gen.Emit(OpCodes.Ldarg_0); 
     gen.Emit(OpCodes.Ldarg_1); 
     gen.Emit(OpCodes.Castclass, field.FieldType); 
     gen.Emit(OpCodes.Stfld, field); 

     gen.Emit(OpCodes.Ret); 
     return (Action<TResult, object>)setterMethod.CreateDelegate(typeof(Action<TResult, object>)); 
    } 
} 

답변

0

보고있는 내용은 사양과 일치합니다. 그들이 초기화 후 일정

initonly 마크 필드 다음 ECMA-335 Section II.16.1.2에서보세요. 이 필드는 생성자 내부에서만 으로 변형되어야합니다. 필드가 정적 필드이면 선언 된 유형의 초기화 자 내부에서만 변형되어야합니다. 인스턴스 필드 인 경우 정의 된 유형의 인스턴스 생성자 중 하나에서만 변형되어야합니다. 파생 클래스의 생성자를 포함하여 다른 모든 생성자에서 다른 방법이나 에서 변형되지 않아야합니다.

[ 참고 : initonly 필드에 ldflda 또는 ldsflda 의 사용은 코드 확인 불가능한에게 있습니다. 확인할 수없는 코드에서 VES는 initonly 필드가 생성자 외부에서 변경되었는지 여부를 확인하지 않아도됩니다. VES는 메서드가 상수의 값을 변경하면 오류를보고하지 않아야합니다. 그러나 같은 코드는 유효하지 않습니다. 끝 참고 ]

이 경우 정상적으로 당신이 FieldInfo.IsInitOnly Property을 사용할 수 있습니다 처리합니다.