如何从列表迁移到 class C# DataContract 序列化?
How do you migrate from a list to a class C# DataContract Serialization?
如何从布尔值列表中将配置迁移到新的 class?以前它使用 bool 列表,但该列表被滥用为 class,每个索引都有特定的含义,如字段。
我想将其从 List 迁移到 class,后者用作用于序列化目的的列表,但将普通字段公开给应用程序的其余部分。
如何编写 class ListEmulator 使其序列化为列表,而不引入新的 xml 标签?
旧代码
namespace
{
[DataContract]
public class Configuration
{
public const string FileName = "Configuration.xml";
public Configuration()
{
AList = new List<bool>();
AGuidList = new List<Guid>();
}
[DataMember]
public List<Guid> AGuidList { get; set; }
[DataMember]
public List<bool> AList { get; set; }
}
}
新代码。
namespace
{
[DataContract]
public class Configuration
{
public const string FileName = "Configuration.xml";
public Configuration()
{
AListEmulator = new ListEmulator();
AGuidList = new List<Guid>();
}
[DataMember]
public List<Guid> AGuidList { get; set; }
[DataMember]
public ListEmulator AListEmulator { get; set; }
}
}
public class ListEmulator
{
public ListEmulator()
{
new ListEmulator(true, true, true, true);
}
public ListEmulator(bool item0, bool item1, bool item2, bool item3)
{
this.IsPlanned = item0;
this.IsCompleted = item1;
this.IsRemaining = item2;
this.IsSerial = item3;
}
public bool IsPlanned { get; set; }
public bool IsCompleted { get; set; }
public bool IsRemaining { get; set; }
public bool IsSerial { get; set; }
}
需要列表的原因是,当只有 1 个元素时需要移植旧的迁移代码,然后是 2、3、4,每个元素具有不同的默认值。如果不是因为我有原始格式的现有部署配置文件,可能是时候在 XML 中单独命名它们了。但是,我现在需要保留当前格式。为了迁移,我想知道如何完成上述操作。
一个选项 是让您的 ListEmulator
继承自 Collection<bool>
,然后添加特定的命名属性以访问数组中的元素,如下所示:
public class ListEmulator : Collection<bool>
{
const bool IsPlannedDefault = false; // Change to the appropriate values.
const bool IsCompletedDefault = false;
const bool IsRemainingDefault = false;
const bool IsSerialDefault = false;
void AddAllDefaults()
{
// Customize the code here to upgrade old collections with fewer than 4 elements to the current 4-element format.
if (Count < 1)
Add(IsPlannedDefault);
if (Count < 2)
Add(IsCompletedDefault);
if (Count < 3)
Add(IsRemainingDefault);
if (Count < 4)
Add(IsSerialDefault);
}
public ListEmulator() { }
public ListEmulator(bool item0, bool item1, bool item2, bool item3)
{
this.IsPlanned = item0;
this.IsCompleted = item1;
this.IsRemaining = item2;
this.IsSerial = item3;
}
public bool IsPlanned { get { return this.ElementAtOrDefault(0, IsPlannedDefault); } set { AddAllDefaults(); this[0] = value; } }
public bool IsCompleted { get { return this.ElementAtOrDefault(1, IsCompletedDefault); } set { AddAllDefaults(); this[1] = value; } }
public bool IsRemaining { get { return this.ElementAtOrDefault(2, IsRemainingDefault); } set { AddAllDefaults(); this[2] = value; } }
public bool IsSerial { get { return this.ElementAtOrDefault(3, IsSerialDefault); } set { AddAllDefaults(); this[3] = value; } }
protected override void InsertItem(int index, bool item)
{
if (index > 3)
throw new ArgumentOutOfRangeException("index > 3");
base.InsertItem(index, item);
}
}
然后在您的 Configuration
中只需将 List<bool>
替换为 ListEmulator
,保留旧元素名称:
[DataMember]
public ListEmulator AList { get; set; }
因为此类型实现了 IEnumerable<T>
,DataContractSerializer
会将其序列化为集合而不是具有属性的对象。 (您可能想要更改 class 名称,因为此时它实际上不是列表 emulator。)但是,这仅在您不添加时有效默认构造函数中集合的任何初始值。
另一种选择 是向 Configuration
添加代理项 属性 来处理必要的转换,并将 ListEmulator AList
标记为不序列化:
[DataContract]
public class Configuration
{
public const string FileName = "Configuration.xml";
public Configuration()
{
AList = new ListEmulator();
AGuidList = new List<Guid>();
}
[DataMember]
public List<Guid> AGuidList { get; set; }
[DataMember(Name = "AList")]
bool[] AlistArray
{
get
{
return AList == null ? null : AList.ToArray();
}
set
{
AList = new ListEmulator(value);
}
}
[IgnoreDataMember] // Do not serialize this property directly
public ListEmulator AList { get; set; }
}
public class ListEmulator
{
const bool IsPlannedDefault = false; // Change to the appropriate values.
const bool IsCompletedDefault = false;
const bool IsRemainingDefault = false;
const bool IsSerialDefault = false;
public ListEmulator(IList<bool> list)
{
IsPlanned = list.ElementAtOrDefault(0, IsPlannedDefault);
IsCompleted = list.ElementAtOrDefault(1, IsCompletedDefault);
IsRemaining = list.ElementAtOrDefault(2, IsRemainingDefault);
IsSerial = list.ElementAtOrDefault(3, IsSerialDefault);
}
public ListEmulator()
{
new ListEmulator(true, true, true, true);
}
public ListEmulator(bool item0, bool item1, bool item2, bool item3)
{
this.IsPlanned = item0;
this.IsCompleted = item1;
this.IsRemaining = item2;
this.IsSerial = item3;
}
public bool IsPlanned { get; set; }
public bool IsCompleted { get; set; }
public bool IsRemaining { get; set; }
public bool IsSerial { get; set; }
public bool[] ToArray()
{
return new[] { IsPlanned, IsCompleted, IsRemaining, IsSerial };
}
}
两个选项都使用以下扩展方法:
public static class ListExtensions
{
public static T ElementAtOrDefault<T>(this IList<T> list, int index, T defaultValue)
{
if (index < 0)
throw new ArgumentOutOfRangeException(string.Format("index = {0}", index));
if (list == null || index >= list.Count)
return defaultValue;
return list[index];
}
}
如何从布尔值列表中将配置迁移到新的 class?以前它使用 bool 列表,但该列表被滥用为 class,每个索引都有特定的含义,如字段。
我想将其从 List 迁移到 class,后者用作用于序列化目的的列表,但将普通字段公开给应用程序的其余部分。
如何编写 class ListEmulator 使其序列化为列表,而不引入新的 xml 标签?
旧代码
namespace
{
[DataContract]
public class Configuration
{
public const string FileName = "Configuration.xml";
public Configuration()
{
AList = new List<bool>();
AGuidList = new List<Guid>();
}
[DataMember]
public List<Guid> AGuidList { get; set; }
[DataMember]
public List<bool> AList { get; set; }
}
}
新代码。
namespace
{
[DataContract]
public class Configuration
{
public const string FileName = "Configuration.xml";
public Configuration()
{
AListEmulator = new ListEmulator();
AGuidList = new List<Guid>();
}
[DataMember]
public List<Guid> AGuidList { get; set; }
[DataMember]
public ListEmulator AListEmulator { get; set; }
}
}
public class ListEmulator
{
public ListEmulator()
{
new ListEmulator(true, true, true, true);
}
public ListEmulator(bool item0, bool item1, bool item2, bool item3)
{
this.IsPlanned = item0;
this.IsCompleted = item1;
this.IsRemaining = item2;
this.IsSerial = item3;
}
public bool IsPlanned { get; set; }
public bool IsCompleted { get; set; }
public bool IsRemaining { get; set; }
public bool IsSerial { get; set; }
}
需要列表的原因是,当只有 1 个元素时需要移植旧的迁移代码,然后是 2、3、4,每个元素具有不同的默认值。如果不是因为我有原始格式的现有部署配置文件,可能是时候在 XML 中单独命名它们了。但是,我现在需要保留当前格式。为了迁移,我想知道如何完成上述操作。
一个选项 是让您的 ListEmulator
继承自 Collection<bool>
,然后添加特定的命名属性以访问数组中的元素,如下所示:
public class ListEmulator : Collection<bool>
{
const bool IsPlannedDefault = false; // Change to the appropriate values.
const bool IsCompletedDefault = false;
const bool IsRemainingDefault = false;
const bool IsSerialDefault = false;
void AddAllDefaults()
{
// Customize the code here to upgrade old collections with fewer than 4 elements to the current 4-element format.
if (Count < 1)
Add(IsPlannedDefault);
if (Count < 2)
Add(IsCompletedDefault);
if (Count < 3)
Add(IsRemainingDefault);
if (Count < 4)
Add(IsSerialDefault);
}
public ListEmulator() { }
public ListEmulator(bool item0, bool item1, bool item2, bool item3)
{
this.IsPlanned = item0;
this.IsCompleted = item1;
this.IsRemaining = item2;
this.IsSerial = item3;
}
public bool IsPlanned { get { return this.ElementAtOrDefault(0, IsPlannedDefault); } set { AddAllDefaults(); this[0] = value; } }
public bool IsCompleted { get { return this.ElementAtOrDefault(1, IsCompletedDefault); } set { AddAllDefaults(); this[1] = value; } }
public bool IsRemaining { get { return this.ElementAtOrDefault(2, IsRemainingDefault); } set { AddAllDefaults(); this[2] = value; } }
public bool IsSerial { get { return this.ElementAtOrDefault(3, IsSerialDefault); } set { AddAllDefaults(); this[3] = value; } }
protected override void InsertItem(int index, bool item)
{
if (index > 3)
throw new ArgumentOutOfRangeException("index > 3");
base.InsertItem(index, item);
}
}
然后在您的 Configuration
中只需将 List<bool>
替换为 ListEmulator
,保留旧元素名称:
[DataMember]
public ListEmulator AList { get; set; }
因为此类型实现了 IEnumerable<T>
,DataContractSerializer
会将其序列化为集合而不是具有属性的对象。 (您可能想要更改 class 名称,因为此时它实际上不是列表 emulator。)但是,这仅在您不添加时有效默认构造函数中集合的任何初始值。
另一种选择 是向 Configuration
添加代理项 属性 来处理必要的转换,并将 ListEmulator AList
标记为不序列化:
[DataContract]
public class Configuration
{
public const string FileName = "Configuration.xml";
public Configuration()
{
AList = new ListEmulator();
AGuidList = new List<Guid>();
}
[DataMember]
public List<Guid> AGuidList { get; set; }
[DataMember(Name = "AList")]
bool[] AlistArray
{
get
{
return AList == null ? null : AList.ToArray();
}
set
{
AList = new ListEmulator(value);
}
}
[IgnoreDataMember] // Do not serialize this property directly
public ListEmulator AList { get; set; }
}
public class ListEmulator
{
const bool IsPlannedDefault = false; // Change to the appropriate values.
const bool IsCompletedDefault = false;
const bool IsRemainingDefault = false;
const bool IsSerialDefault = false;
public ListEmulator(IList<bool> list)
{
IsPlanned = list.ElementAtOrDefault(0, IsPlannedDefault);
IsCompleted = list.ElementAtOrDefault(1, IsCompletedDefault);
IsRemaining = list.ElementAtOrDefault(2, IsRemainingDefault);
IsSerial = list.ElementAtOrDefault(3, IsSerialDefault);
}
public ListEmulator()
{
new ListEmulator(true, true, true, true);
}
public ListEmulator(bool item0, bool item1, bool item2, bool item3)
{
this.IsPlanned = item0;
this.IsCompleted = item1;
this.IsRemaining = item2;
this.IsSerial = item3;
}
public bool IsPlanned { get; set; }
public bool IsCompleted { get; set; }
public bool IsRemaining { get; set; }
public bool IsSerial { get; set; }
public bool[] ToArray()
{
return new[] { IsPlanned, IsCompleted, IsRemaining, IsSerial };
}
}
两个选项都使用以下扩展方法:
public static class ListExtensions
{
public static T ElementAtOrDefault<T>(this IList<T> list, int index, T defaultValue)
{
if (index < 0)
throw new ArgumentOutOfRangeException(string.Format("index = {0}", index));
if (list == null || index >= list.Count)
return defaultValue;
return list[index];
}
}