2012-02-14 42 views
8

連載讓我們假設我有例如序列化水平的汽車類的一個對象內部和公共。公共級別的一些屬性不應該被序列化,因爲它們是內部的。決定其性能在運行時

此時的「最簡單」的方式,我能想到的實現這一目標是通過繼承:

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

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

然後,我可以

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

的ToSerialize的結果()被取由一個框架(我沒有 控制)並序列化爲JSON或XML。

我爲了簡化省略XML序列化屬性。

這感覺就像一個黑客和黑客帶你只有這麼遠。有沒有更好的方法(方法?)來實現這一目標?

我認爲它清除了,但我想避免編寫JSON和XML我自己的序列化方法。

在此先感謝 Tymek

==編輯

爲了澄清,我希望能夠序列化多層次:

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; 
} 

==選擇方法

我標誌着馬克Gravell的答案的答案,因爲它提供瞭如何C#泛型信息和它的「標準」的組件都支持我提出的要求。

但是我認爲對於我的問題最好的方法是使用如上所示的代理類,並且 使用以下方法在此多級模式中序列化類。

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

這允許保持Car0..3類非常簡單,只有性能,維護和理解。

+1

編寫自定義序列化方法是我所知道的更好的方法(並且確實不是那麼困難)。你有自定義的序列化需求,它可以自己定製的序列化器...是否有一個特定的原因,你不想沿着這條路徑走下去? – Bill 2012-02-14 05:08:24

+0

主要原因是我在框架環境中,序列化應該由框架完成,而我只是將結果作爲對象返回。 – mayu 2012-02-14 05:19:12

+0

你能看到這個環境中的其他類正在做什麼來解決這個問題嗎?如果你要破解它,也可能像其他人一樣破解它:) – Bill 2012-02-14 05:40:50

回答

5

這很大程度上取決於您正在使用的序列化框架。你提到XML和JSON - 好,首先要注意的事情是,你可以與裝飾:

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

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

XmlSerializerJavascriptSerializer將響應。如果你需要在每個實例的基礎上決定,有ShouldSerialize**Specified模式:

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

上面是基於名稱的模式,所使用的XmlSerializer等;它有一個雙胞胎:

[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 */ } 
} 

你不需要做任何事情來連接它們 - 他們自動工作。

不同的串行器允許不同的模式。

此外,有時您可以在運行時添加諸如[XmlIgnore]的內容 - 例如,通過XmlAttributeOverrides或任何給定序列化程序的等效項。

+0

我將此標記爲回答問題的答案,但我在問題本身中將我選擇的方法描述爲==選擇的方法。 – mayu 2012-03-01 03:28:35

0

你可以用這表明它們應納入(或根據您的要求忽略不計),然後在你的ToSerialize檢查屬性自定義屬性裝飾你的內部屬性。

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

那麼最終的類定義看起來像:

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

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

ToSerialize看起來是這樣的:

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

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

ShouldSerialize可能看起來像:

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

更新基於在評論@比爾的洞察力

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

這應該由當前只返回聲明的屬性列表:如果你只希望序列化公共屬性時levelLevel.Public您可以通過反映使用BindingFlags.DeclaredOnly標誌類型的屬性達到這樣的效果car的實例。

+1

我不認爲這回答了這個問題。他需要根據所需級別序列化一組不同的屬性,而不僅僅是公開序列化。 – Bill 2012-02-14 06:37:28

+0

@Bill - 在問題中哪裏說(或者當我回答時是否說)? OP發佈的代碼不會實現這一點,那麼是什麼讓你認爲這是他們想要的?除非我已經讀過代碼的意圖。 – 2012-02-14 06:40:40

+0

@M在他的代碼中,他返回CarInternal(所有屬性被序列化)或CarPublic(只有公共屬性被序列化)。請參閱他的ToSerialize方法,該方法根據Level.Public進行選擇。 – Bill 2012-02-14 06:43:48