【问题标题】:C# constructors having both shared and different code具有共享代码和不同代码的 C# 构造函数
【发布时间】:2020-03-14 08:25:09
【问题描述】:

有没有一种方法可以构造以下类,使我可以只对ServiceValues 的设置进行一次编码:

public class MyClass
{
    private readonly IService Service;
    public List<int> Values { get; set; }
    public int Value { get; set; }

    public MyClass(IService service, List<int> values)
    {
        Service = service;
        Values = values;
        Value = Values.FirstOrDefault(i => i == Service.GetDefaultValue());
    }

    public MyClass(IService service, List<int> values, int value)
    {
        Service = service;
        Values = values;
        Value = Values.FirstOrDefault(i => i == value);
    }
}

【问题讨论】:

  • Constructor Chaning 是您应该寻找的机器人。

标签: c# constructor


【解决方案1】:

您可以使用构造函数链接:

public class MyClass
{
    public MyClass(IService service, IEnumerable<int> values) 
      : this(service, values, valus.FirstOrDefault(i => i == service.GetDefaultValue()) {}

    public MyClass(IService service, IEnumerable<int> values, int value)
    {
        Service = service;
        Values = values;
        Value = value;
    }
}

请注意,我已将 values 参数指定为 IEnumerable 而不是 List。这允许 ctor 接受比列表更多的类型。如果您的成员是 List 类型,则必须在构造函数中调用 ToList() 方法。 不过,我还建议您将 Values 属性指定为 IEnumerable 而不是 List。

编辑:更改问题中的代码后,另一个建议可能是使用私有构造函数和(重载)静态工厂方法。这样做表明(恕我直言)创建这样的实例是一个更“昂贵”的操作,而不是调用简单的构造函数,因为您正在调用“DataService”上的方法,这表明您可能会去数据库初始化你的对象?

public class NewExpenseViewModel
{
    private readonly IDataService DataService;

    public ExpenseType ExpenseType { get; set; }

    CollectionViewSource VatRatesSource { get; set; }
    public ICollectionView VatRatesView => VatRatesSource.View;

    private NewExpenseViewModel(ServiceProvider serviceProvider, ExpenseType expenseType, VatRate vatRate)
    {
        DataService = serviceProvider.GetService<IDataService>();

        ExpenseType = expenseType;

        VatRatesSource = new CollectionViewSource() { Source = DataService.GetVatRates() };

        VatRate = vatRate;
    }

    public static NewExpenseViewModel Create(ServiceProvider sp, ExpenseType expenseType, VatRate vat)
    {
        DataService = serviceProvider.GetService<IDataService>();

        ExpenseType = expenseType;

        VatRatesSource = new CollectionViewSource() { Source = DataService.GetVatRates() };

        VatRate = vatRate;
    }


    public static NewExpenseViewModel Create(ServiceProvider sp, ExpenseType expenseType)
    {
        var instance = Create(sp, expenseType, 0);
        instance.Vat = 
            ((IEnumerable<VatRate>)VatRatesSource.Source).FirstOrDefault(v => v.VatRateID.Equals(ExpenseType.SuggestedVatRateID));

        return instance;
    }
}

【讨论】:

  • 谢谢,Frederik - +1 - 虽然不幸的是我不得不移动球门柱,因为我的实际课程有点复杂,我发布了一个过于简化的版本。你能帮忙做第二个版本吗?
  • 再想一想,我会问一个新问题。再次感谢。
  • 您提供的第二个解决方案似乎没有编译,抱怨非静态Create 不返回值,静态版本需要VatRatesSource 的对象引用等。我实际上,通过意识到我正在将对象传递给第三个参数,我根据您的其他答案提出了一个解决方案,其中我只需要一个 int 作为 ID(我将把它作为答案发布)。谢谢!
【解决方案2】:

在意识到我只需要一个int 作为第三个参数之后,我按照 Frederik 的策略得出的解决方案:

public NewExpenseViewModel(ServiceProvider serviceProvider, ExpenseType expenseType, int vatRateID)
{
    DataService = serviceProvider.GetService<IDataService>();

    ExpenseType = expenseType;

    VatRatesSource = new CollectionViewSource() { Source = DataService.GetVatRates() };

    VatRate = VatRates.FirstOrDefault(v => v.VatRateID.Equals(vatRateID));
}

public NewExpenseViewModel(ServiceProvider serviceProvider, ExpenseType expenseType)
    : this(serviceProvider, expenseType, expenseType.SuggestedVatRateID) { }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-09-26
    • 2020-02-29
    • 1970-01-01
    • 1970-01-01
    • 2014-04-21
    • 2017-12-17
    • 2022-01-23
    • 2018-09-10
    相关资源
    最近更新 更多