Renaming of class property that is marked with a DataMemberAttribute

老子叫甜甜 提交于 2020-01-30 07:53:07

问题


Actually i have a class like this

[DataContract]
public class Item : IExtensibleDataObject
{
    [Browsable(false)]
    public virtual ExtensionDataObject ExtensionData { get; set; }

    [DataMember]
    public string ID { get; set; }

    [DataMember]
    public string Name { get; set; }

    public Item()
        : this(String.Empty, String.Empty)
    { }

    public Item(string id, string name)
    {
        ID = id ?? String.Empty;
        Name = name ?? String.Empty;
    }
}

You can easily serialize and deserialize it. But now comes the hard part:

I have to rename the property Name to FullName and every new xml serialized file should come out with the FullName while it is still possible to read in the old files.

To get the new property name out into a new file is quite easy. Just rename the property and you're done.

For compatibility i would mark the new property name with [DataMember(Name="Name")] but in this case if i write this class back into a file i got the old name written.

So exists there something in the DataContract where i can mark my property FullName maybe twice like

[DataMember(Name="Name")]
[DataMember]
public string FullName { get; set}

or is there any other mechanism how i can show that both values can be written into this, but only one will come out on writing back?

The only way i can imagine of would be to create a class LegacyItem which has no functions or something like this, but fulfills the old DataContract. Additionally some kind of implicit/explicit operator to convert my LegacyItem into an Item. Last but not least on deserializing i have to make some tests (maybe just a simple try/catch) to find out what class i should tell the DataContractSerializer to read in the file.

So even if this approach would be possible it sounds a little bit overcomplicated for this task and i'm wondering if there isn't something already available within the framework that would make this task a little bit easier.


回答1:


If you don't mind having a little obsolete code in your class (which anyway would be less code than the entire second class that you suggested) then you can do this:

[DataContract]
public class Item : IExtensibleDataObject
{
    public virtual ExtensionDataObject ExtensionData { get; set; }

    [DataMember]
    public string ID { get; set; }

    [DataMember(Name = "Name", EmitDefaultValue = false)]
    private string _obsoleteName { get { return null; } set { if(value != null) FullName = value; } }

    [DataMember]
    public string FullName {get; set;}

    public Item()
        : this(String.Empty, String.Empty)
    { }

    public Item(string id, string name)
    {
        ID = id ?? String.Empty;
        FullName = name ?? String.Empty;
    }
}

The old XML can be read in, and on deserialize will properly assign to your new property. Then when serializing, only the new property will be serialized as FullName via the set accessor. When serializing, the old property always returns null, and is not event emitted to the serialized XML.

Also you can mark the obsolete property as private so that it is not visible outside of the class.

A couple of tips going forward, I prefer to not use automatic property for DataMember properties. In fact I usually mark the backing field as the DataMember. It is probably best to ALWAYS include the optional Name parameter for the DataMember attribute. I confess I do not always do this myself, but it is a good practice, because then you don't accidentally break your contract if you Refactor -> Rename a property or field in Visual Studio.

UPDATE

The OP Oliver suggested another solution himself ... here is what that looks like for those interested.

[DataContract]
public class Item : IExtensibleDataObject
{
    public virtual ExtensionDataObject ExtensionData { get; set; }

    [DataMember]
    public string ID { get; set; }

    [DataMember(Name = "Name", EmitDefaultValue = false)]
    private string _obsoleteName;

    [DataMember]
    public string FullName {get; set;}

    public Item()
        : this(String.Empty, String.Empty)
    { }

    public Item(string id, string name)
    {
        ID = id ?? String.Empty;
        FullName = name ?? String.Empty;
    }

    [OnDeserialized]
    void OnDeserialized(StreamingContext context)
    {
        if(_obsoleteName != null && FullName == null)
        {
            //upgrade old serialized object to new version
            //by copying serialized Name field to newer FullName
            FullName = _obsoleteName;

            //set _obsoleteName to null so that it stops serializing
            _obsoleteName = null;
        }
    }
}



回答2:


You should look at the IExtensibleDataObject interface and the corresponding ExtensionDataObject field. It will require some custom code to make it work properly, but will help resolve your issue.



来源:https://stackoverflow.com/questions/3447565/renaming-of-class-property-that-is-marked-with-a-datamemberattribute

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!