【问题标题】:C# - How can I set a List to have at least one element? [duplicate]C# - 如何将列表设置为至少包含一个元素? [复制]
【发布时间】:2015-12-08 19:22:08
【问题描述】:

我有以下问题:

我有一个名为MedicalInfo 的类,我希望它的列表至少有一个Prescription。问题是我想在它的构造函数中加入一些逻辑,如下所示,但它有一个主要缺点:当我反序列化它(xml)时,它会添加一个新的。

我想序列化程序首先创建对象(因此总是添加一个Prescription 的实例),然后添加字段的值。所以,简而言之,每次我反序列化时都会得到一个额外的实例......我该如何避免这种情况?

只是为了说明一些上下文,我正在开发一个 WinForms 应用程序,该应用程序在应用程序关闭时序列化并在其打开时反序列化,以便在其使用期间提供可用的数据。此外,MedicalInfo 是名为Client 的类的一部分,该类具有许多属性,例如策略列表。我序列化和反序列化的是客户端列表(地址簿)。我想在反序列化后进行“检查”……但在某些情况下,这需要双 foreach。我不确定这是否是最佳选择。

public class MedicalInfo
{
    public string MedicareNumber { get; set; }
    public DateTime PartAEffectiveDate { get; set; }
    public DateTime PartBEffectiveDate { get; set; }
    public List<Prescription> Prescriptions { get; set; }

    public MedicalInfo()
    {
        PartAEffectiveDate = new DateTime(1900, 01, 01);
        PartBEffectiveDate = new DateTime(1900, 01, 01);
        Prescriptions = new List<Prescription>().Min(1);

        if (Prescriptions.Count == 0)
        {
            Prescriptions.Add(new Prescription());
            Prescriptions.FirstOrDefault().Instructions = "Default Prescription";
        }
    }
}

public class Client
{
    #region Properties

    private Guid ID { get; set; }

    [XmlIgnore]
    public string FullName
    {
        get
        {
            return FirstName + " " + MiddleName + " " + LastName;
        }
    }
    [XmlIgnore]
    public string DisplayName
    {
        get
        {
            return LastName + ", " + FirstName;
        }
    }

    public string FirstName { get; set; }
    public string MiddleName { get; set; }
    public string LastName { get; set; }
    public bool Male { get; set; }
    public DateTime Birthday { get; set; }
    public Address Address { get; set; }
    public int SSN { get; set; }
    public long Phone { get; set; }
    public long AlternatePhone { get; set; }
    public string Email { get; set; }
    public int Height { get; set; }
    public int Weight { get; set; }
    public string Notes { get; set; }

    public BankAccount BankInfo { get; set; }
    public MedicalInfo MedInfo { get; set; }

    public DateTime RegisteredTime { get; set; }

    #endregion Properties

    public Client()
    {
        ID = new Guid();
        RegisteredTime = DateTime.Now;

        Birthday = new DateTime(1900, 01, 01);
        BankInfo = new BankAccount();
        MedInfo = new MedicalInfo();
        Address = new Address();
    }
}

public class InsuranceClient : Client
{
    public bool Tobacco { get; set; }
    public PolicyCollection Policies { get; set; }

    public InsuranceClient() : base()
    {
        Policies = new PolicyCollection();

        if (Policies.Count == 0)
        {
            Policies.Add(new Policy());
            Policies.FirstOrDefault().Plan = "Default Policy";
        }
    }
}

【问题讨论】:

  • 一个简单的选择是将您的 Policies 属性设为私有并创建另一个公开它的公共属性,但也处理返回单个“默认策略”集合的空案例
  • 我会将该逻辑移出构造函数。唯一需要确保至少有一个项目的地方是第一次创建全新的(保险)客户时。因此,将其移至负责创建该对象的工厂/构建器。
  • 哦,谢谢@Mark,我没想到!也许使用 Client 和 InsuranceClient 的工厂方法?那真的很有启发性。谢谢! :)
  • @JavierGarcíaManzano -- 有正确答案吗?

标签: c# list serialization


【解决方案1】:

您需要从构造函数中删除初始化。我建议使用null-coalescing operator ??,详情如下。

public class MedicalInfo
{
    public string MedicareNumber { get; set; }
    public DateTime PartAEffectiveDate { get; set; }
    public DateTime PartBEffectiveDate { get; set; }

    public List<Prescription> Prescriptions
    {
        get
        {
            return _prescritpions ?? (_prescritpions = GetDefaultPrescriptions());
        }
        set
        {
            _prescritpions = value;
        }
    }
    List<Prescription> _prescritpions;

    public MedicalInfo()
    {
        PartAEffectiveDate = new DateTime(1900, 01, 01);
        PartBEffectiveDate = new DateTime(1900, 01, 01);
    }

    static List<Prescription> GetDefaultPrescriptions()
    {
        return new List<Prescription> 
               { 
                   new Prescription { Instructions = "Default Description" }     
               };
    }
}

优点是如果_perscriptions 变量已经被实例化——它会简单地返回。否则,如果它是null,它将使用GetDefaultPrescriptions 函数中指定的默认实例来实例化它。这应该可以防止重复创建与序列化问题相同的默认变量。

【讨论】:

  • 感谢大卫,这绝对是更快的解决方案。我以不同的方式解决了它,实现了工厂方法,因为我想到了它,这要归功于以前的 cmets 之一,但这是一个很好的解决方案。再次感谢! :)
【解决方案2】:

添加一个成员变量来存储您的处方。将业务规则添加到 Prescriptions 属性的 getter。

public class MedicalInfo
{
    public string MedicareNumber { get; set; }
    public DateTime PartAEffectiveDate { get; set; }
    public DateTime PartBEffectiveDate { get; set; }

    private List<Prescription> _prescritpions;
    public List<Prescription> Prescriptions
    {
        get
        {
            if (_prescritpions.Count == 0)
            {
                _prescritpions.Add(new Prescription
                {
                    Instructions = "Default Description"
                });
            }

            return _prescritpions;
        }
        set
        {
            _prescritpions = value;
        }
    }

    public MedicalInfo()
    {
        PartAEffectiveDate = new DateTime(1900, 01, 01);
        PartBEffectiveDate = new DateTime(1900, 01, 01);

        _prescritpions = new List<Prescription>();
    }
}

编辑:从构造函数中删除了不必要的处方实例化。

【讨论】:

    猜你喜欢
    • 2020-05-01
    • 1970-01-01
    • 2020-07-27
    • 2011-01-30
    • 1970-01-01
    • 1970-01-01
    • 2015-07-23
    • 1970-01-01
    • 2020-03-25
    相关资源
    最近更新 更多