عدم الحصول على حقول من GetType (). getfields مع bindingflag.default
-
18-09-2019 - |
سؤال
أنا أستخدم فئات الانعكاس من أجل الحصول على جميع الحقول داخل كائن معين. ومع ذلك، فإن مشكلتي هي أنه يعمل تماما عندما تكون الحقول داخل فئة طبيعية، مثل:
class test
{
string test1 = string.Empty;
string test2 = string.Empty;
}
هنا أحصل على كل من Test1 و Test2، مشكلتي هي أنني أستخدم التجريد وبالتالي عدة فصول مجتمعة.
حصلت على شيء مثل:
class test3 : test2
{
string test4 = string.Empty;
string test5 = string.Empty;
}
class test2 : test1
{
string test2 = string.Empty;
string test3 = string.Empty;
}
class test1
{
string test0 = string.Empty;
string test1 = string.Empty;
}
ولكن عندما أجريها، لا أحصل على الحقول مرة أخرى من GetType().GetFields(BindingFlag.Default)
.
لدى كل من هذه الحقول أيضا ممتلكات، get; set;
أضفها له. عندما أقوم بتشغيل التعليمات البرمجية، أحصل على الخصائص مرة أخرى إلى Test1 ولكن ليس الحقول الفعلية.
هذا هو الكود الذي أحاول الحصول على الحقول مع:
FieldInfo[] fields = Obj.GetType().GetFields(BindingFlags.Default);
foreach (FieldInfo field in fields)
لقد حاولت أيضا:
FieldInfo[] fields = Obj.GetType().GetFields(BindingFlags.Public
| BindingFlags.Instance
| BindingFlags.NonPublic
| BindingFlags.Static);
يمكنني استخدام نفس الرمز للخصائص:
PropertyInfo[] properties = Obj.GetType().GetProperties(BindingFlags.Public
| BindingFlags.Instance
| BindingFlags.NonPublic
| BindingFlags.Static);
foreach (PropertyInfo property in properties)
أي أفكار لماذا أحصل على الممتلكات من الفئات المستخرجة ولكن ليس الحقول؟
المحلول
تحرير: للحصول على نشر أعضاء من النوع الأساسي، يجب عليك:
typeof(T).BaseType.GetFields(...)
تحرير مرة أخرى: الفوز.
تحرير 3/22/13: المستخدمة Concat
بدلا من Union
. وبعد لأننا نحدد BindingFlags.DeclaredOnly
ونوع BaseType
لا يمكن أن يساوي نفسه، Union
ليست هناك حاجة وهي أكثر تكلفة.
public static IEnumerable<FieldInfo> GetAllFields(Type t)
{
if (t == null)
return Enumerable.Empty<FieldInfo>();
BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
BindingFlags.Static | BindingFlags.Instance |
BindingFlags.DeclaredOnly;
return t.GetFields(flags).Concat(GetAllFields(t.BaseType));
}
نصائح أخرى
لا يمكن للنوع الذي يرث نوعا آخر رؤية أجزاء خاصة من هذا النوع الآخر، فيمكنه رؤية الأجزاء المحمية والداخلية والعامة. النظر في التعليمات البرمجية التالية:
class A
{
// note that this field is private
string PrivateString = string.Empty;
// protected field
protected string ProtectedString = string.Empty;
}
class B : A { }
class Program
{
static void Main(string[] args)
{
Console.WriteLine("B Fields:");
B b = new B();
b.GetType()
.GetFields(BindingFlags.NonPublic | BindingFlags.Instance)
.ToList()
.ForEach(f => Console.WriteLine(f.Name));
Console.WriteLine("A Fields:");
A a = new A();
a.GetType()
.GetFields(BindingFlags.NonPublic | BindingFlags.Instance)
.ToList()
.ForEach(f => Console.WriteLine(f.Name));
}
}
إخراج هذا البرنامج هو ما يلي:
B Fields:
ProtectedString
A Fields:
PrivateString
ProtectedString
لذلك، النوع A
لديه حقلين؛ PrivateString
و ProtectedString
. وبعد اكتب B
لديه واحد؛ ProtectedString
, ، أن يرث من A
. وبعد إذا كنت ترغب في "الوصول" PrivateString
من خلال النوع B
, ، سوف تحتاج إلى الانتقال إلى نوع الأساس (b.GetType().BaseType
).
ملاحظة رغم ذلك، حتى لو كان النوع B
تقارير أن يكون لديك حقل يسمى ProtectedString
, ، لا يزال هذا الحقل غير معلن B
; ؛ أعلن في A
. وبعد يمكن فحص هذا عن طريق إضافة BindingFlags.DeclaredOnly
إلى GetFields
يدعو في برنامج العينة أعلاه؛ GetFields
سوف ترجع أي مجالات ل B
, ، واثنان ل A
.
ترجم إلى نموذج الكود الخاص بك، وهذا يعني أن النوع test3
لا يحتوي على الحقول test2
و test3
, ، لأنها خاصة إلى النوع test2
(تشابه أسماء الحقول ونوع الأسماء تجعل هذه الجملة مربكة إلى حد ما، أخشى).
يمكنك استخدام طريقة التمديد هذه لإعادة تكرار التسلسل الهرمي للميراث من النوع، وكل الطريق إلى الكائن، وإرجاع جميع مجالات النوع وجميع أسلافها بشكل فعال:
public static class ReflectionExtensions
{
public static IList<FieldInfo> GetAllFields(this Type type, BindingFlags flags)
{
if(type == typeof(Object)) return new List<FieldInfo>();
var list = type.BaseType.GetAllFields(flags);
// in order to avoid duplicates, force BindingFlags.DeclaredOnly
list.AddRange(type.GetFields(flags | BindingFlags.DeclaredOnly));
return list;
}
}
(غير مختبر، YMMV)
الخصائص موروثة، الحقول ليست كذلك. الحقول المحمية مرئية لفصول الدرسات، ولكن لا تورثها. وبعبارة أخرى، فإن فئة SLECALDY لديها بالفعل خصائص فئةها الأساسية، لكنها مجرد قادرة على رؤية الحقول.
إذا كنت تريد فقط الأسماء لكل من الخصائص والحقول، استخدم
private static IEnumerable<string > GetAllFieldsAndProperties(Type t)
{
if (t == null)
return Enumerable.Empty<string>();
BindingFlags flags = BindingFlags.Public
| BindingFlags.NonPublic
| BindingFlags.Static
| BindingFlags.Instance
| BindingFlags.DeclaredOnly;
return t.GetFields(flags).Select(x=>x.Name)
.Union(GetAllFieldsAndProperties(t.BaseType))
.Union(t.GetProperties(flags).Select(x=>x.Name));
}
تعداد جميع الحقول من النوع بما في ذلك الأعضاء الخاصين من الفصول الأساسية.
public static IEnumerable<FieldInfo> EnumerateFields(this Type type, BindingFlags flags) =>
type.BaseType?.EnumerateFields(flags)
.Concat(type.GetFields(flags | BindingFlags.DeclaredOnly)) ??
type.EnumerateFields(flags);