2012-02-14 29 views
8

Giả sử tôi phải sắp xếp thứ tự một đối tượng của một lớp Ô tô ở các cấp, ví dụ: Nội bộ và Công cộng. Một số thuộc tính ở cấp Công cộng không được tuần tự hóa vì chúng là nội bộ.Quyết định các thuộc tính nào được tuần tự hóa tại thời gian chạy

Tại thời điểm này cách 'dễ nhất' tôi có thể nghĩ ra để đạt được điều này là sử dụng thừa kế:

class CarPublic { 
    public int PropX {get;set} 
} 

class CarInternal: CarPublic { 
    public string PropY {get;set} 
} 

Sau đó, tôi có thể

object ToSerialize() { 
CarInternal car = GetCar(); 
if(level == Level.Public) { 
    return car as CarPublic; 
} else { 
    return car; 
} 
} 

Kết quả của ToSerialize() được thực hiện bởi một khuôn khổ (tôi không có kiểm soát) và được tuần tự hóa thành JSON hoặc XML.

Tôi bỏ qua các thuộc tính tuần tự hóa XML để đơn giản.

Điều này giống như một hack và hack chỉ đưa bạn đến nay. Có cách nào tốt hơn (cách nào?) Để đạt được điều này?

Tôi nghĩ rõ ràng bây giờ, nhưng tôi muốn tránh viết các phương thức tuần tự hóa riêng của mình cho JSON và XML.

Cảm ơn trước Tymek

EDIT ==

Để làm rõ, tôi muốn để có thể serialize nhiều cấp độ:

class Car0 { 
    public int PropA {get;set} 
} 

class Car1: Car0 { 
    public string PropB {get;set} 
} 

class Car2: Car1 { 
    public int PropC {get;set} 
} 

class Car3: Car2 { 
    public string PropD {get;set} 
} 

object ToSerialize(Level level) { 
Car3 car = GetCar(); 
switch(level) { 
    case Level.Zero: return car as Car0; 
    case Level.One: return car as Car1; 
    case Level.Two: return car as Car3; 
    case Level.Three: return car as Car4; 
} 
return null; 
} 

== Cách tiếp cận được chọn

Tôi đã đánh dấu câu trả lời của Marc Gravell là câu trả lời, vì nó cung cấp thông tin chung về cách C# và các thành phần 'chuẩn' hỗ trợ những gì tôi đã yêu cầu. Tuy nhiên, tôi nghĩ cách tiếp cận tốt nhất cho vấn đề của tôi là sử dụng các lớp proxy như được trình bày ở trên và có lớp được sắp xếp theo kiểu đa cấp này với các phương pháp như được hiển thị bên dưới. Hình minh hoạ.

public interface ICar { 
    Car0 As0(); 
    Car1 As1(); 
    Car2 As2(); 
    Car3 As3(); 
... 
} 

này cho phép giữ Car0..3 lớp rất đơn giản, chỉ với tài sản, để duy trì và hiểu được.

+1

Viết các phương thức tuần tự hóa tùy chỉnh là cách tốt hơn mà tôi biết (và thực sự không phải là điều khó khăn). Bạn có yêu cầu serialization tùy chỉnh mà chính nó cho một serializer tùy chỉnh ... Có một lý do cụ thể mà bạn không muốn đi xuống con đường đó? – Bill

+0

Lý do chính là tôi đang ở trong môi trường khung nơi việc tuần tự hóa nên được thực hiện bởi khung công tác và tôi chỉ trả lại kết quả dưới dạng đối tượng. – mayu

+0

Bạn có thể thấy những lớp khác trong môi trường này đang làm gì để giải quyết vấn đề này không? Nếu bạn định hack nó thành từng mảnh, cũng có thể hack nó theo cách tương tự như những người khác có :) – Bill

Trả lời

5

Điều này phụ thuộc rất nhiều vào khung tuần tự hóa bạn đang sử dụng. Bạn đề cập đến xml và json - tốt, điều đầu tiên cần lưu ý là bạn chỉ có thể trang trí với:

[XmlIgnore] 
public int PropX {get;set;} 

hoặc

[ScriptIgnore] 
public int PropX {get;set;} 

XmlSerializerJavascriptSerializer sẽ trả lời. Nếu bạn cần phải đưa ra quyết định trên cơ sở mỗi sơ thẩm, có ShouldSerialize**Specified mẫu:

public bool ShouldSerializePropX() { 
    // return true to serialize, false to omit 
} 

Trên đây là một mô hình tên dựa trên, được sử dụng bởi XmlSerializer và những người khác; nó có một đôi:

[XmlIgnore, Browsable(false)] 
public bool PropXSpecified { 
    get { /* return true to serialize, false to omit */ } 
    set { /* can just drop this value - don't need to assign */ } 
} 

Bạn không cần phải làm bất cứ điều gì để kết nối chúng - chúng hoạt động tự động.

Trình nối tiếp khác nhau cho phép các mẫu khác nhau.

Ngoài ra, đôi khi bạn có thể thêm những thứ như [XmlIgnore] khi chạy - ví dụ: qua XmlAttributeOverrides hoặc tương đương với bất kỳ bộ nối tiếp cụ thể nào.

+0

Tôi đã đánh dấu câu trả lời này là câu trả lời vì câu trả lời cho câu hỏi, nhưng tôi đã mô tả cách tiếp cận đã chọn của tôi trong câu hỏi đó là == Lựa chọn được chọn. – mayu

0

Bạn có thể trang trí thuộc tính Nội bộ của mình bằng thuộc tính tùy chỉnh cho biết rằng chúng phải được bao gồm (hoặc bỏ qua tùy thuộc vào yêu cầu của bạn) và sau đó trong ToSerialize kiểm tra thuộc tính.

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)] 
public class ShouldSerializeAttribute : Attribute { } 

Sau đó, kết quả định nghĩa lớp học của bạn sẽ trông như thế:

class Car 
{ 
    [ShouldSerialize] 
    public int PropX {get;set} 

    // This property won't be serialized because it is internal 
    public int PropY { get; set; } 
} 

Bạn ToSerialize sẽ giống như thế:

object ToSerialize() 
{ 
    Car car = GetCar(); 

    foreach(PropertyInfo propInfo in car.GetType().GetProperties()) 
    { 
     if(ShouldSerialize(propInfo)) 
     { 
      return car; 
     } 
    } 
} 

đâu ShouldSerialize có thể trông giống như:

internal bool ShouldSerialize(PropertyInfo propInfo) 
{ 
    return propInfo.GetCustomAttributes(typeof(ShouldSerializeAttribute), true).FirstOrDefault() != null; 
} 

CẬP NHẬT

Dựa trên @ cái nhìn sâu sắc của Bill trong các ý kiến. Nếu bạn đang tìm kiếm để chỉ serialize thuộc tính nào khi levelLevel.Public bạn có thể đạt được hiệu quả mà bằng cách phản chiếu trên thuộc tính của loại sử dụng BindingFlags.DeclaredOnly cờ:

foreach(PropertyInfo propInfo in car.GetType().GetProperties(BindingFlags.DeclaredOnly)) 

này sẽ trả về một danh sách các thuộc tính chỉ tuyên bố bởi hiện tại bản sao của car.

+1

Tôi không nghĩ rằng điều này sẽ trả lời câu hỏi.Anh ta cần tuần tự hóa một tập hợp các thuộc tính khác nhau dựa trên mức yêu cầu, không chỉ tuần tự hóa nếu công khai. – Bill

+0

@Bill - Câu hỏi đặt ra ở đâu (hoặc đã nói khi tôi trả lời)? Mã OP được đăng sẽ không đạt được điều này vì vậy điều gì khiến bạn nghĩ rằng đó là những gì họ muốn? Trừ khi tôi đã đọc được ý định của mã. –

+0

@M Trong mã của mình, anh ta trả về hoặc CarInternal (tất cả các thuộc tính được serialized) hoặc CarPublic (chỉ có các thuộc tính công khai được serialized). Xem phương pháp ToSerialize của mình, tạo nên sự lựa chọn dựa trên Level.Public. – Bill

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