DataContract Type Property Serialization

How can I effectively serialize a Type property in my attribute of the DataContract class? I assume Type is a non-serializable type (wow, which gets a dumb sound.) I am sure there is a way to do this that meets my needs. Basically I need to serialize the type name for the factory method for efficient construction, but I don't want to expand it as a string, I want a type.

I know that there are several ways to do this, I'm curious what other methods are currently known.

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

Enter "System.RuntimeType" with the data contract name "RuntimeType: http://schemas.datacontract.org/2004/07/System" not expected. Consider using a DataContractResolver or add any types that are not statically known to the list of known types β€” for example, using the KnownTypeAttribute attribute or by adding them to the list of known types passed to the 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 consumption of the viewmodel.

 [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); } } 
+7
source share
3 answers

Type cannot be expressed in a cross-platform manner, so it does not have an inline representation. It is best 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); } } 
+10
source

In the root class, add the KnownType attribute with System.RuntimeType passed as the type.

In C #,

 [KnownType(typeof(System.RuntimeType))] 
0
source

What you can also do, especially if you do not want to change PlottingDeviceInfo , is to pass an IDataContractSurrogate in the DataContractSerializer constructor. What I did (I don't know if there is an easier way) is to define

 public class TypeWrapper { public string TypeName; } 

and then use it like this:

 public class TypeReplacementSurrogate : IDataContractSurrogate { public object GetCustomDataToExport(Type clrType, Type dataContractType) { return null; } public object GetCustomDataToExport(MemberInfo memberInfo, Type dataContractType) { return null; } public Type GetDataContractType(Type type) { if(type == typeof(Type)) { return typeof (TypeWrapper); } return type; } public object GetDeserializedObject(object obj, Type targetType) { var objAsTypeWrapper = obj as TypeWrapper; if (objAsTypeWrapper != null) { return Assembly.GetExecutingAssembly().GetType(objAsTypeWrapper.TypeName); } return obj; } public void GetKnownCustomDataTypes(System.Collections.ObjectModel.Collection<Type> customDataTypes) { } public object GetObjectToSerialize(object obj, Type targetType) { var objAsType = obj as Type; if (objAsType != null) { return new TypeWrapper() {TypeName = objAsType.FullName}; } return obj; } public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData) { return null; } public System.CodeDom.CodeTypeDeclaration ProcessImportedType( System.CodeDom.CodeTypeDeclaration typeDeclaration, System.CodeDom.CodeCompileUnit compileUnit) { return null; } } 
0
source

All Articles