2013-05-07 33 views
11

Có thể đánh dấu một thuộc tính trong lớp cơ sở với một số thuộc tính vẫn còn hiệu quả trong các lớp con không?Làm tăng tác dụng của thuộc tính để ghi đè các thuộc tính trong các lớp con

Câu hỏi có thể rất cụ thể đối với Sê-ri hóa, nhưng tôi chắc chắn nghĩ rằng cũng có thể có các cách sử dụng khác.

Xét đoạn mã sau:

using System; 
using System.IO; 
using System.Xml.Serialization; 

namespace Code.Without.IDE 
{ 
    [Serializable] 
    public abstract class C1 
    { 
     [XmlIgnore] 
     public abstract bool IsValid_C1 { get; set;} 
    } 

    [Serializable] 
    public class C2 : C1 
    { 
     public bool IsValid_C2 { get; set; } 

     public override bool IsValid_C1 { get; set;} 

     public C2() 
     { 
      IsValid_C1 = true; 
      IsValid_C2 = false; 
     } 
    } 

    public static class AbstractPropertiesAttributeTest 
    { 
     public static void Main(string[] args) 
     { 
      C2 c2 = new C2(); 
      using(MemoryStream ms = new MemoryStream()) 
      { 
       XmlSerializer ser = new XmlSerializer(typeof(C2)); 
       ser.Serialize(ms, c2); 
       string result = System.Text.Encoding.UTF8.GetString(ms.ToArray()); 
       Console.WriteLine(result); 
      } 
     } 
    } 
} 

trên trả về mã:

------ C:\abhi\Code\CSharp\without IDE\AbstractPropertiesAttributeTest.exe 
<?xml version="1.0"?> 
<C2 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <IsValid_C2>false</IsValid_C2> 
    <IsValid_C1>true</IsValid_C1> 
</C2> 
------ Process returned 0 

Tôi nghĩ IsValid_C1 sẽ bị bỏ qua, mặc dù nó không phải là như vậy. Có cách nào để đạt được điều này ngoài việc đánh dấu tài sản là được bảo vệ không?

Chỉnh sửa: Mã nhanh để hiển thị rằng XmlIgnore khả năng hiển thị đang được kế thừa. http://ideone.com/HH41TE

+2

Nếu 'XmlIgnoreAttribute' đã được khai báo bằng' Inherited = true', điều này sẽ hoạt động. Than ôi, nó không phải là, và đây không phải là một cách để làm cho nó hoạt động: http://ideone.com/B0KASa '[AttributeUsageAttribute (AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue, Inherited = true) ] lớp công khai XmlInheritIgnoreAttribute: System.Xml.Serialization.XmlIgnoreAttribute { } ' –

+0

@TimS. Tôi đã thử mã của bạn và như bạn đã đề xuất đúng, nó không hoạt động trong tình huống này có lẽ bởi vì nó không được thiết kế cho điều này? – Abhinav

+0

@abhinav Đủ công bằng, không nhận ra. –

Trả lời

1

Tôi không tin rằng có cách để kế thừa thuộc tính vì bạn ghi đè thuộc tính lớp cơ sở. Bạn sẽ cần phải trang trí IsValid_C1 của C2 với XmlIgnore:

[Serializable] 
    public class C2 : C1 
    { 
     public bool IsValid_C2 { get; set; } 

     [XmlIgnore] 
     public override bool IsValid_C1 { get; set; } 

     public C2() 
     { 
      IsValid_C1 = true; 
      IsValid_C2 = false; 
     } 
    } 
+3

Trừ khi một thuộc tính được đánh dấu là * un * 'Inheritable', nó sẽ tự động được xếp vào các lớp dẫn xuất. Khi tôi thực hiện một số phản chiếu trên trường IsValid_C1, mặc dù hơi khác một chút, tôi có thể thấy rằng nó được đánh dấu bằng 'XmlIgnoreAttribute'. Tôi tin rằng XmlSerializer không nhìn thuộc tính này giống như tôi đã làm. Tôi đồng ý rằng đoạn mã trên là một trong các giải pháp nếu tôi cần làm cho nó hoạt động với 'XmlSerializer'. – Abhinav

+0

Tôi không biết điều đó và được thực hiện tốt để phản ánh mã để kiểm tra, cảm ơn bạn. +1 cho bạn. :) –

1

Tôi sẽ cung cấp một cái nhìn khác về câu hỏi này. Có lẽ bạn chỉ sử dụng các thuộc tính đó làm ví dụ và muốn có các thuộc tính severall được xếp tầng. Nhưng tôi nghĩ rằng đây có thể là thời điểm tốt để suy nghĩ về mô hình kế thừa được đề xuất. Một cách cơ bản, bạn có thể sử dụng kế thừa thường xuyên hoặc suy nghĩ về một số mẫu thiết kế, có thể không giải quyết vấn đề liên quan đến serialization, nhưng có thể cung cấp cho bạn một số "khớp nối lỏng lẻo" trong ứng dụng của bạn, làm cho nó thành một mô hình thành phần hơn và allowwing mỗi lớp để đối phó chỉ với những gì là mối quan tâm, bằng cách này bạn có thể tái sử dụng rất nhiều thứ và làm cho cuộc sống của bạn dễ dàng hơn.

Dựa trên suy nghĩ đó, im cung cấp cho bạn mẫu của Mẫu thiết kế trang trí được trộn lẫn với Mẫu thiết kế chiến lược. Nếu được phát triển các lớp học như những người trên mẫu của bạn, đây là làm thế nào tôi sẽ làm điều đó:

/// <summary> 
    /// The interface for validation strategy (since we are using interface, there is no need for another abstract class) 
    /// </summary> 
    public interface IValidation 
    { 
     bool IsValid { get; set; } 
    } 

    /// <summary> 
    /// The decorator (it dont need to be abstract) that has the serializable properties 
    /// </summary> 
    [Serializable] 
    public class ValidatableDecorator : IValidation 
    { 
     protected IValidation instance; 

     public ValidatableDecorator() 
     { 
      Init(); 
     } 
     public ValidatableDecorator(IValidation instance) 
     { 
      Init(); 
     } 

     protected virtual void Init() { } 

     public void Set(IValidation instance) 
     { 
      this.instance = instance; 
     } 

     [XmlIgnore] 
     public bool IsValid 
     { 
      get 
      { 
       return instance.IsValid; 
      } 
      set 
      { 
       instance.IsValid = value; 
      } 
     } 
    } 

Sau đó, bạn cần phải thực hiện một số lớp học có logic của mẫu chiến lược, như thế này:

public class BossValidatorImplementation : IValidation 
    { 

     public bool IsValid 
     { 
      get 
      { 
       return false; ; 
      } 
      set 
      { 
       throw new InvalidOperationException("I dont allow you to tell me this!"); 
      } 
     } 
    } 

    public class EasyGoingValidator : IValidation 
    { 
     public bool IsValid { get; set; } 
    } 

Bây giờ chúng ta có logic tách ra khỏi lớp học, chúng ta có thể kế thừa từ các trang trí, lựa chọn chiến lược mà họ sử dụng để lĩnh vực IsValid, như thế này:

public class ChildWithBossValidation : ValidatableDecorator 
    { 
     protected ChildWithBossValidation(IValidation instance) 
      : this() 
     { 
      Init(); 
     } 

     public ChildWithBossValidation() 
      : base(new BossValidatorImplementation()) 
     { 
      Init(); 
     } 

     protected override void Init() 
     { 
      Name = "I'm the boss!"; 
      Sallary = 10000d; 
     } 

     public string Name { get; set; } 
     public double Sallary { get; set; } 

    } 

    public class ChildWithEasyGoingValidation : ValidatableDecorator 
    { 
     public ChildWithEasyGoingValidation() 
      : base(new EasyGoingValidator()) 
     { 
     } 
     protected ChildWithEasyGoingValidation(IValidation instance) 
      : this() 
     { 
     } 

     protected override void Init() 
     { 
      Name = "Do as you please... :) "; 
     } 

     public string Name { get; set; } 
    } 

Đây là mã t o cho thấy các giải pháp hoạt động:

public static void Main(string[] args) 
    { 

     var boos = new ChildWithBossValidation(); 
     var coolGuy = new ChildWithEasyGoingValidation(); 

     using (var ms = new MemoryStream()) 
     { 
      var ser = new XmlSerializer(boos.GetType()); 
      ser.Serialize(ms, boos); 
      string result = System.Text.Encoding.UTF8.GetString(ms.ToArray()); 
      Console.WriteLine("With override"); 
      Console.WriteLine(result); 
     } 

     Console.WriteLine("-------------"); 

     using (var ms = new MemoryStream()) 
     { 
      var ser = new XmlSerializer(coolGuy.GetType()); 
      ser.Serialize(ms, coolGuy); 
      string result = System.Text.Encoding.UTF8.GetString(ms.ToArray()); 
      Console.WriteLine("With override"); 
      Console.WriteLine(result); 
     } 

     Console.ReadKey(); 
    } 

Kết quả là:

{<?xml version="1.0"?> 
<ChildWithBossValidation xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <Name>I'm the boss!</Name> 
    <Sallary>10000</Sallary> 
</ChildWithBossValidation>-------------------<?xml version="1.0"?> 
<ChildWithEasyGoingValidation xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <Name>Do as you please... :) </Name> 
</ChildWithEasyGoingValidation>} 

Vì vậy, có lẽ đây không trả lời như thế nào để thác các thuộc tính trong trường hợp này (vì bạn có thể dễ dàng làm điều đó bằng cách tạo của bạn thuộc tính riêng (đánh dấu để cho phép thừa kế) và sau đó triển khai một số mã vào SerializeXML). Đây chỉ là một tùy chọn khác có thể cải thiện kiến ​​trúc tổng thể của các giải pháp bằng cách sử dụng Pattern Design.Nhưng điều này giải quyết vấn đề cụ thể này cũng :)

1

Một hành vi cần thiết có thể đạt được bằng cách sử dụng các lớp XmlAttributeOverrides và XmlAttributes. Tôi đã viết phương pháp helper để tạo XmlSerializer:

public static XmlSerializer GetXmlSerializerWithXmlIgnoreFields(Type t) 
    { 
     XmlAttributeOverrides xmlOverrides = new XmlAttributeOverrides(); 

     foreach (var prop in t.GetProperties(BindingFlags.Public|BindingFlags.Instance)) 
     { 
      Attribute xmlIgnoreAttribute = Attribute.GetCustomAttribute(prop, typeof(XmlIgnoreAttribute)); 
      if (xmlIgnoreAttribute == null) 
       continue; 

      XmlAttributes xmlAttributes = new XmlAttributes(); 
      xmlAttributes.XmlIgnore = true; 
      xmlOverrides.Add(t, prop.Name, xmlAttributes); 
     } 

     return new XmlSerializer(t, xmlOverrides); 
    } 

Phương pháp chính đã trở thành:

public static void Main(string[] args) 
    { 
     C2 c2 = new C2(); 
     using (MemoryStream ms = new MemoryStream()) 
     { 
      XmlSerializer ser = GetXmlSerializerWithXmlIgnoreFields(typeof(C2)); 
      ser.Serialize(ms, c2); 
      string result = System.Text.Encoding.UTF8.GetString(ms.ToArray()); 
      Console.WriteLine(result); 
     } 
    } 
0

Nó xuất hiện tính năng này được chia trong C#.

Bạn có thể viết thuộc tính thông qua sự phản chiếu sẽ làm giảm các thuộc tính cho bạn. Khá thẳng về phía trước nếu bạn hiểu được sự phản chiếu.

Các vấn đề liên quan