C# 如何从列表迁移到C类#DataContract序列化?

C# 如何从列表迁移到C类#DataContract序列化?,c#,serialization,datacontractserializer,C#,Serialization,Datacontractserializer,如何将配置从布尔列表迁移到新类?以前它使用bool列表,但该列表作为一个类被滥用,每个索引都有一个特定的含义,比如一个字段 我想将它从一个列表迁移到一个类,该类在序列化时充当列表,但向应用程序的其余部分公开普通字段 如何编写类ListMulator,使其序列化为列表,而不引入新的xml标记 旧代码 namespace { [DataContract] public class Configuration { public const string File

如何将配置从布尔列表迁移到新类?以前它使用bool列表,但该列表作为一个类被滥用,每个索引都有一个特定的含义,比如一个字段

我想将它从一个列表迁移到一个类,该类在序列化时充当列表,但向应用程序的其余部分公开普通字段

如何编写类ListMulator,使其序列化为列表,而不引入新的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; }
    }
}
名称空间
{
[数据合同]
公共类配置
{
public const string FileName=“Configuration.xml”;
公共配置()
{
AList=新列表();
AGuidList=新列表();
}
[数据成员]
公共列表列表{get;set;}
[数据成员]
公共列表列表{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; }
}
名称空间
{
[数据合同]
公共类配置
{
public const string FileName=“Configuration.xml”;
公共配置()
{
AListEmulator=新建ListSimulator();
AGuidList=新列表();
}
[数据成员]
公共列表列表{get;set;}
[数据成员]
公共ListSimulator{get;set;}
}
}
公共类监听器
{
公共ListSimulator()
{
新ListSimulator(真,真,真,真);
}
公共ListSimulator(布尔项0、布尔项1、布尔项2、布尔项3)
{
this.IsPlanned=item0;
this.IsCompleted=第1项;
this.IsRemaining=item2;
此.IsSerial=第3项;
}
公共布尔值已规划{get;set;}
公共布尔已完成{get;set;}
公共bool正在生成{get;set;}
公共布尔值序列{get;set;}
}

需要列表的原因是,当只有1个元素,然后是2、3、4个元素时,需要移植旧的迁移代码,每个元素都有不同的默认值。如果不是因为我已经以原始格式部署了现有的配置文件,那么可能是时候用XML分别命名它们了。但是,我现在需要保留当前的格式。为了迁移,我想知道如何才能完成上述操作。

一个选项是让您的
ListMulator继承,然后添加特定的命名属性来访问数组中的元素,如下所示:

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);
    }
}
由于此类型实现了
IEnumerable
,因此
DataContractSerializer
将其序列化为集合,而不是具有属性的对象。(您可能需要更改类名,因为此时它实际上不是列表仿真器。)但是,只有在不从默认构造函数向集合添加任何初始值的情况下,这才有效

另一个选项是将代理属性添加到处理必要转换的
配置
,并将
ListMulator列表
标记为未序列化:

[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 };
    }
}
[DataContract]
公共类配置
{
public const string FileName=“Configuration.xml”;
公共配置()
{
AList=新的ListSimulator();
AGuidList=新列表();
}
[数据成员]
公共列表列表{get;set;}
[DataMember(Name=“AList”)]
布尔数组
{
得到
{
返回AList==null?null:AList.ToArray();
}
设置
{
AList=新的ListSimulator(值);
}
}
[IgnoreDataMember]//不要直接序列化此属性
公共ListEmulator AList{get;set;}
}
公共类监听器
{
const bool isplannedefault=false;//更改为适当的值。
const bool iscompletedefault=false;
const bool IsRemainingDefault=false;
const bool IsSerialDefault=假;
公共ListSimulator(IList列表)
{
IsPlanned=list.ElementAtOrDefault(0,isplannededefault);
IsCompleted=list.ElementAtOrDefault(1,iscompletededefault);
IsRemaining=list.ElementAtOrDefault(2,IsRemainingDefault);
IsSerial=list.ElementAtOrDefault(3,IsSerialDefault);
}
公共ListSimulator()
{
新ListSimulator(真,真,真,真);
}
公共ListSimulator(布尔项0、布尔项1、布尔项2、布尔项3)
{
this.IsPlanned=item0;
this.IsCompleted=第1项;
this.IsRemaining=item2;
此.IsSerial=第3项;
}
公共布尔值已规划{get;set;}
公共布尔已完成{get;set;}
公共bool正在生成{get;set;}
公共布尔值序列{get;set;}
公共图书馆[]ToArray()
{
返回新[]{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];
    }
}
公共静态类ListExtensions
{
公共静态T ElementAtOrDefault(此IList列表,int索引,T defaultValue)
{
如果(指数<0)
抛出新ArgumentOutOfRangeException(string.Format(“index={0}”,index));
if(list==null | | index>=list.Count)
返回默认值;
返回列表[索引];
}
}

您的意思是,您希望您的XML继续具有
bool
值的数组,还是希望您的XML更改为实际显示有意义的元素名称,如
true
,并在读取时正确升级?在您编写的问题的开头,您希望在不引入新的xml标记的情况下实现这一点,但在后面编写的问题中,可能是时候在xml中分别命名它们了。你想要哪一个?第一个。主要是出于教育原因。知道如何读第一个,但写第二个,以及读第二个会很好。事实上,第二个在我看来更容易,但我会看看我是否能回答这个问题
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];
    }
}