2013-03-01 3 views
8

FormatterServices.GetSerializableMembers은 파생 된 유형에 대해 보호 된 필드와 내부 필드를 두 번 반환합니다. 한 번은 SerializationFieldInfo의 인스턴스로, 한 번은 RtFieldInfo으로 표시됩니다.GetSerializableMembers (FormatterServices)는 동일한 필드를 두 번 반환합니다! 왜?

매우 혼란 스럽습니다. Microsoft가 왜이 방법을 구현하기로 결정했는지 이해하는 사람은 누구든지 나를 도울 수 있습니까?

class Program 
{ 
    [Serializable] 
    public class BaseA 
    { 
     private int privateField; 
    } 

    [Serializable] 
    public class DerivedA : BaseA { } 

    [Serializable] 
    public class BaseB 
    { 
     protected int protectedField; 
    } 

    [Serializable] 
    public class DerivedB : BaseB { } 

    static void Main(string[] args) 
    { 
     Program.PrintMemberInfo(typeof(DerivedA)); 
     Program.PrintMemberInfo(typeof(DerivedB)); 
     Console.ReadKey(); 
    } 

    static void PrintMemberInfo(Type t) 
    { 
     Console.WriteLine(t.Name); 

     foreach (var mbr in FormatterServices.GetSerializableMembers(t)) 
     { 
      Console.WriteLine(" {0} ({1})", mbr.Name, mbr.MetadataToken); 
     } 

     Console.WriteLine(); 
    } 
} 

내가 privateFieldprotectedField 한 번 각을보고 있다는 기대 :

나는 내 문제를 생산할 다시 샘플 프로그램을 작성했습니다.

 
DerivedA 
    BaseA+privateField (67108865) 

DerivedB 
    protectedField (67108866) 
    BaseB+protectedField (67108866) 

당신이 protectedField 다른 이름으로하지만 같은 메타 데이터를 두 번 나타날 볼 수 있듯이 토큰 그래서 그것은 참으로 바로 그 분야이다 : 그러나이 프로그램을 실행 실제 출력이다.

이유를 설명 할 수 있습니까?

+0

분명히 이것은 한동안 알려져 있습니다. http://msdn.microsoft.com/en-us/library/2bb1dc1s(v=vs.90).aspx (의견 섹션). –

+0

하지만 여전히 설명이 없습니다 ... :-( –

답변

1

이것은 FormatterServices와 많이 관련이있는 것 같지는 않지만 반영이 작동하는 방식과 FormatterServices에서 사용되는 방식에 관한 것 같습니다. BindingFlags.NonPublic (http://msdn.microsoft.com/en-us/library/6ztex2dc.aspx 참조)과 함께 사용하는 경우 Type.GetFields 메서드의 경우 : "기본 클래스의 보호 된 내부 필드 만 반환되며 기본 클래스의 개인 필드는 반환되지 않습니다."

가 완전히 수표 박탈하고 예에 맞게, 필드를 얻기 위해 무엇을 FormatterServices 기본적으로 :

DerivedA 
1 Reflected: BaseA - Declaring: BaseA - Field: privateField (67108865) 

DerivedB 
1 Reflected: DerivedB - Declaring: BaseB - Field: protectedField (67108866) 
2 Reflected: BaseB - Declaring: BaseB - Field: protectedField (67108866) 

: 귀하의 예제 클래스의 다음과 같은 출력을 생성

static IEnumerable<FieldInfo> GetSerializableFields(Type type, Func<Type, IEnumerable<FieldInfo>> andNext) 
    { 
     return 
      (type.IsInterface || type == typeof(object)) 
      ? new FieldInfo[0] 
      : type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) 
        .Where(f => (f.Attributes & FieldAttributes.NotSerialized) != FieldAttributes.NotSerialized) 
        .Concat(andNext(type)); 
    } 

    static void PrintMemberInfo(Type t) 
    { 
     Console.WriteLine(t.Name); 

     Func<Type, IEnumerable<FieldInfo>> andNext = null; 
     andNext = tp => GetSerializableFields(tp.BaseType, andNext); 
     var fields = GetSerializableFields(t, tp => new FieldInfo[0]).ToArray(); 
     var base_fields = GetSerializableFields(t.BaseType, andNext).ToArray(); 

     var counter = 0; 
     foreach (var f in fields.Concat(base_fields)) 
     { 
      Console.WriteLine(
       "{0} Reflected: {1} - Declaring: {2} - Field: {3} ({4})", 
       (counter++) + 1, f.ReflectedType.Name, f.DeclaringType.Name, f.Name, f.MetadataToken); 
     } 
     Console.WriteLine(); 
    } 
} 

FormatterServices는 동일한 선언 유형의 동일한 필드가 두 번 이상 포함되는지 여부를 확인하여 결과를 필터링하지 않습니다. FormatterServices가 구현되는 방식 (형식의 serializable 기본 형식에 대한 검사 수행)을 감안할 때 ReflectedType == DeclaringType :

에 의해 필터와 같은 작업을 수행해야합니다.

+0

예, 필터링을 수행하는 것을 잊은 것처럼 보입니다. 연구 노력에 감사드립니다. –

0

몇 가지 각도에서 테스트 한 후 필자는 대답을 변경하기로 결정했습니다.

GetSerializableMembers() 메서드가 잘못되었습니다. 중복이 기본 메모리의 올바른 투영이 아닙니다. (정말 놀라운 일이다 ..)

내가 사용하는 것이 좋습니다 : t.GetType()를 GetMembers을 (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).

회원 목록에 대한 결과를 확인하십시오.

행운을 비네.

+0

답변 주셔서 감사합니다. 그러나 "... 접근 수정 자에 관계없이 [Serializable]이라고 표시된 모든 파생 개체 멤버를 가져옵니다."- 해석 방법은 실제로 동일한 필드가 두 번 이상 반환되는 곳에서 메서드가 반환하는 것에 대해 말합니다. 중복이 흥미롭거나 혼동을 일으키지 않는 단일 사용 사례는 생각할 수 없습니다. 그러한 예제를 제공 할 수 있습니다. –

+0

충분히 좋았습니다. 예제를 추가했는데 예제 나 사례 사용이 실제로 문제가되지 않았습니다. 질문은 다음과 같습니다. 개발자 또는 사람이 객체를 시각화하거나 물리적으로 메모리에 저장하는 방법 –

+0

내 질문에 요점을 놓치고 있다고 생각합니다. 중복되는 것으로 간주되는 필드는 동일한 메타 데이터 토큰을 가지고 있기 때문에 실제로 동일한 멤버를 참조합니다. 당신은 두 개의 별도 필드 (다른 메타 데이터 토큰)를 게시 했으므로 거기에 중복 된 것이 없습니다. –

관련 문제