Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DataContract serialization of property of "Type"

How can I effectively serialize a property of type "Type" in my DataContract attributed class? I'm assuming that Type is a non-serializable Type (wow that's getting silly sounding.) I'm sure that there is a way to do this that meets my needs. Basically I need to serialize the name of a type for a factory method to effectively construct, but I don't want to expose it as a string, I want a Type.

I know there are a number of ways to do this, I'm curious what other methods are known at this time.

EDIT: I just realized it may be something else causing it but here is the error, and below I have the class definition.

Type 'System.RuntimeType' with data contract name 'RuntimeType:http://schemas.datacontract.org/2004/07/System' is not expected. Consider using a DataContractResolver or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.

[DataContract]
public class PlottingDeviceInfo : ObservableObject
{
    private string _deviceName;
    [DataMember]
    public string DeviceName
    {
        get
        {
            return _deviceName;
        }
        set
        {
            Set(() => DeviceName, ref _deviceName, value);
        }
    }

    private Type _deviceType;
    [DataMember]
    public Type DeviceType
    {
        get
        {
            return _deviceType;
        }
        set
        {
            Set(() => DeviceType, ref _deviceType, value);
        }
    }

    private DeviceSettingsInfo _settings;
    [DataMember]
    public DeviceSettingsInfo Settings
    {
        get
        {
            return _settings;
        }
        set
        {
            Set(() => Settings, ref _settings, value);
        }
    }

    private DeviceChannelInfo _channel;
    [DataMember]
    public DeviceChannelInfo Channel
    {
        get
        {
            return _channel;
        }
        set
        {
            Set(() => Channel, ref _channel, value);
        }
    }

    private DeviceCategory _deviceCategory;
    [IgnoreDataMember]
    public DeviceCategory DeviceCategory
    {
        get
        {
            return _deviceCategory;
        }
        set
        {
            Set(() => DeviceCategory, ref _deviceCategory, value);
        }
    }
}

Here is the base class, used to add observability for viewmodel consumption.

[DataContract]
public class ObservableObject : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    [IgnoreDataMember]
    protected PropertyChangedEventHandler PropertyChangedHandler
    {
        get
        {
            return PropertyChanged;
        }
    }

    [Conditional("DEBUG")]
    [DebuggerStepThrough]
    public void VerifyPropertyName(string propertyName)
    {
        var myType = this.GetType();
        if (!string.IsNullOrEmpty(propertyName)
            && myType.GetProperty(propertyName) == null)
        {
            throw new ArgumentException("Property not found", propertyName);
        }
    }

    protected virtual void RaisePropertyChanged(string propertyName)
    {
        VerifyPropertyName(propertyName);

        var handler = PropertyChanged;

        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    protected virtual void RaisePropertyChanged<T>(Expression<Func<T>> propertyExpression)
    {
        if (propertyExpression == null)
        {
            return;
        }

        var handler = PropertyChanged;

        if (handler != null)
        {
            var body = propertyExpression.Body as MemberExpression;
            handler(this, new PropertyChangedEventArgs(body.Member.Name));
        }
    }

    protected void Set<T>(
        Expression<Func<T>> propertyExpression,
        ref T field,
        T newValue)
    {
        if (EqualityComparer<T>.Default.Equals(field, newValue))
        {
            return;
        }

        field = newValue;
        RaisePropertyChanged(propertyExpression);
    }

    protected void Set<T>(
        string propertyName,
        ref T field,
        T newValue)
    {
        if (EqualityComparer<T>.Default.Equals(field, newValue))
        {
            return;
        }

        field = newValue;
        RaisePropertyChanged(propertyName);
    }
}
like image 651
Firoso Avatar asked Sep 20 '11 16:09

Firoso


People also ask

What is DataContract and DataMember?

A datacontract is a formal agreement between a client and service that abstractly describes the data to be exchanged. In WCF, the most common way of serialization is to make the type with the datacontract attribute and each member as datamember.

What is DataContract Attribute in C#?

[DataContract] attribute specifies the data, which is to serialize (in short conversion of structured data into some format like Binary, XML etc.) and deserialize(opposite of serialization) in order to exchange between the client and the Service.

How does serialization work in C#?

Serialization is the process of converting an object into a stream of bytes to store the object or transmit it to memory, a database, or a file. Its main purpose is to save the state of an object in order to be able to recreate it when needed. The reverse process is called deserialization.


1 Answers

Type cannot be expressed in a cross-platform way, so it has no inbuilt representation. Your best bet is to represent it as a string, i.e.

public Type DeviceType { get; set; }
[DataMember(Name="DeviceType")]
private string DeviceTypeName {
    get { return DeviceType == null ? null : DeviceType.AssemblyQualifiedName; }
    set { DeviceType = value == null ? null : Type.GetType(value); }
}
like image 105
Marc Gravell Avatar answered Sep 20 '22 17:09

Marc Gravell