Câu hỏi Ẩn và phản xạ thuộc tính (C #)


Khai báo một thuộc tính trong một lớp dẫn xuất khớp với tên của một thuộc tính trong lớp cơ sở "ẩn" nó (trừ khi nó ghi đè nó bằng override từ khóa). Cả thuộc tính cơ sở và lớp dẫn xuất sẽ được trả về bởi Type.GetProperties() nếu loại của chúng không khớp. Tuy nhiên, nếu các loại của chúng làm phù hợp, gây sốc chỉ có thuộc tính của lớp dẫn xuất được trả về. Ví dụ:

class A
{
    protected double p;
    public int P { get { return (int)p; } set { p = value; } }
}
class B : A
{
    public new int P { get { return (int)p; } set { p = value; } }
}
class C : B
{
    public new float P { get { return (float)p; } set { p = value; } }
}

Đang gọi typeof(C).GetProperties() sẽ chỉ trả về B.P và C.P. Có thể gọi GetProperties() theo cách trả về cả ba? Có gần như chắc chắn là một cách để làm điều đó bằng cách đi qua các hệ thống phân cấp thừa kế, nhưng có một giải pháp sạch hơn?


19
2018-04-26 16:16


gốc


Tại sao bạn muốn có một hệ thống phân cấp lớp như vậy? - driis
@ driis: Đây chỉ là một ví dụ nhỏ để minh họa. Nhưng, vì lợi ích của lập luận, giả sử hệ thống phân cấp lớp này được viết bởi một ai đó khác với tôi, nhưng tôi vẫn cần phải tìm tất cả các thuộc tính công khai của nó, ngay cả những thuộc tính ẩn. - Eric Mickelsen
Vì không có cách nào sử dụng lớp dẫn xuất, bạn có thể truy cập thuộc tính ẩn mà tôi cho rằng hiệu quả nó không có thuộc tính đó cho Reflection. Xem xét cho mình may mắn, VB chỉ cho thấy C.P khi sử dụng Shadows. - Wilhelm
@ Wilhelm: Nhưng bạn có thể truy cập tài sản ẩn: C c = new C (); ((A) c) .P = 42; - Eric Mickelsen
Bạn đã thử sử dụng BindingFlags.FlattenHierarchy chưa? Điều đó nói rằng, không trả lại tài sản có vẻ giống như hành vi chính xác, vì nó có thể bị ẩn vì một lý do. - Dan Bryant


Các câu trả lời:


GetProperties được định nghĩa là tất cả các thuộc tính công khai của loại.

Bạn có thể nhận được và thiết lập các phương thức của họ bằng cách sử dụng:

typeof(C).GetMethods()
         .Where(m => m.Name.StartsWith("set_") || m.Name.StartsWith("get_"))

Mặc dù điều này có vẻ như một ý tưởng tồi, so với việc đi xuống hệ thống phân cấp thừa kế để có được các thuộc tính.


6
2018-04-26 16:48



Sau đó, bạn sẽ có cùng một vấn đề với phương pháp get_P ẩn một trong những phụ huynh, tôi nghĩ. - driis
@Yuriy: typeof (C) .GetMethods () .Đâu @driis: Không, có vẻ như nó hoạt động đúng. - Eric Mickelsen
Tôi vừa thử nó. Tôi nhận được tất cả 6. - Yuriy Faktorovich
Bạn đúng rồi. Phương pháp này cũng hoạt động. Không hoàn toàn chắc chắn lý do tại sao nó hoạt động, vì tôi giả định cùng một phương pháp ẩn quy tắc đi cho phương pháp cũng như tài sản. Hmm. - driis
Điều này sẽ làm việc cho tôi nếu tôi có thể nhận được tại PropertyInfo từ getter hoặc setter. - Eric Mickelsen


Tôi không nghĩ rằng nó có thể mà không đi qua các hệ thống phân cấp thừa kế. Nó không phải là quá nhiều mã, mặc dù:

    public static IEnumerable<PropertyInfo> GetAllProperties(Type t)
    {
        while (t != typeof(object))
        {
            foreach (var prop in t.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance))
                yield return prop;
            t = t.BaseType;
        }
    }

Tất nhiên, nếu bạn biết một basetype phổ biến, bạn có thể dừng lại, thay vì đối tượng, nó sẽ hiệu quả hơn. Cũng thế; nó sẽ mất một thời gian để làm các phản ánh, do đó, bộ nhớ cache kết quả. Sau khi tất cả, thông tin loại sẽ không thay đổi trong khi thực thi.


5
2018-04-26 16:58



Liệu điều này có mang lại các thuộc tính bị ghi đè nhiều lần không? - Eric Mickelsen
Không, bởi vì anh ta nói BindingFlags.DeclaredOnly. - Yuriy Faktorovich
Vấn đề ở đây là nếu chúng ta viết lại phân cấp lớp để B.P ghi đè A.P, chúng ta vẫn nhận được ba thuộc tính mặc dù một đối tượng kiểu C bây giờ chỉ có hai. - Eric Mickelsen
Ngược lại, Yuriy, câu trả lời của bạn sẽ chỉ mang lại hai bộ get / setters, đó là hành vi đúng. - Eric Mickelsen
Bạn nói đúng, tôi hiểu sai những gì bạn nói. Tôi cũng đã thử nghiệm phương pháp của mình và nó chỉ trả về hai. - Yuriy Faktorovich


Thông qua phản ánh, từ khóa mới chỉ ẩn thuộc tính được thừa kế nếu chữ ký khớp với nhau. Tôi đoán phản chiếu phù hợp với chữ ký trên accessors tài sản (get_ & set_). Đó là lý do tại sao GetProperties() trả về B.P và C.P khi kiểu trả về khác nhau.

Gần đây tôi đã phát hiện ra Fasteflect cung cấp cơ chế phản chiếu nâng cao.

Tôi đã kiểm tra và Fasteflect type.Properties trả về tất cả các cây của các thành viên ẩn (P). Tôi nghĩ rằng API xem xét việc sao lưu các thành viên (ảo / ghi đè) và các thành viên ẩn (mới) khác nhau mà là một điều tốt cho 'vấn đề' của bạn;)

Thử nghiệm của tôi với trang web nhanh hơn:

class Class1
{
    public object field1 = null;

    public virtual object Property1 { get; set; }

    public object Property2 { get; set; }

    public string Property3 { get; set; }
}

class Class2 : Class1
{
    public new object field1 = null;

    public override object Property1 { get; set; }

    public new string Property3 { get; set; }
}

class Class3 : Class2
{
    public new string Property3 { get; set; }
}

Lọc thành viên sao lưu nhưng trả về tất cả thành viên bị ẩn:

typeof(Class3).Properties(Flags.ExcludeBackingMembers | Flags.Public | Flags.Instance) 
  • typeof (Class3) .Properties (Flags.ExcludeBackingMembers | Flags.Public | Flags.Instance) Count = 5 System.Collections.Generic.IList
    • [0] {System.String Property3} System.Reflection.PropertyInfo 
    • [1] {System.Object Property1} System.Reflection.PropertyInfo 
    • [2] {System.String Property3} System.Reflection.PropertyInfo 
    • [3] {System.Object Property2} System.Reflection.PropertyInfo 
    • [4] {System.String Property3} System.Reflection.PropertyInfo 

2
2018-05-04 11:42



msdn.microsoft.com/en-us/library/… : Một hằng số, trường, thuộc tính hoặc kiểu được giới thiệu trong một lớp hoặc cấu trúc ẩn tất cả các thành viên lớp cơ sở có cùng tên. - Eric Mickelsen
Không thông qua sự phản chiếu. Vì các thuộc tính là accessors, tôi đoán sự phản chiếu khớp với chữ ký trên các phương thức accessor (get_ & set_). - JoeBilly
Sau khi kiểm tra và kiểm tra Fasterflect, tôi có thể nói rằng câu trả lời của họ cho vấn đề này hoàn toàn tương đương với vấn đề của driis. Giải pháp đệ quy của họ để tìm kiếm các thành viên ẩn là không có khả năng loại trừ các thuộc tính ảo đã bị ghi đè. (Trên thực tế, đặt cờ ExcludeBackingMembers bằng cách nào đó loại trừ tất cả ba thuộc tính trong cả hai trường hợp.) Tuy nhiên, cảm ơn liên kết. - Eric Mickelsen
Thật lạ lùng, tôi đã thêm bài kiểm tra của mình vào bài đăng. Tôi đã kiểm tra lại và ExcludeBackingMembers không loại trừ các thành viên ẩn. Tôi đã thử mà không có tính chất tự động quá: hành vi tương tự. - JoeBilly
Thú vị - nó đã làm việc tốt hơn nhiều với chính xác những lá cờ bạn đã sử dụng. Tuy nhiên, nó vẫn thất bại trong thử nghiệm của tôi. Nếu bạn ẩn thuộc tính bị ghi đè, nó vẫn biến mất. (Thêm đối tượng công khai mới Property1 vào Class3 của bạn.) Vì vậy, trong thực tế, vẫn còn các thuộc tính ở đó có thể được sử dụng, nhưng không hiển thị đối với sự phản chiếu. - Eric Mickelsen