如何使用第二个构造函数实例化具有无参数构造函数和带有可选参数的第二个构造函数的类?

时间:2020-02-14 00:44:01

标签: c# .net

我使用的第三方SDK具有包含多个构造函数的类。它具有无参数的构造函数,并且具有另一个构造函数,其所有属性均设置为默认值(AKA可选参数)。这是一个示例:

    public class MyClass
    {
        public MyClass() { }

        public MyClass(int i = 1) { }
    }

在我看来,如果我通过new MyClass()创建此类的实例,它将仅使用无参数构造函数。那么我到底如何/为什么可以用可选参数来调用那个?

烦人的是,第二个步骤对我需要调用的类进行了额外的设置,但是我不需要更改参数的默认值。因此,看来我唯一的选择是仅将第一个参数的值硬编码为标记为默认值的值,以便可以使用该构造函数。即,在上面的简单示例中,我被迫做new MyClass(1)

这只是对设计不良的SDK的一种抱怨。但是我想我可以把它扔出去看看你们是否知道我还能在不将第二个ctor硬编码为相同默认值的情况下调用第二个ctor。

3 个答案:

答案 0 :(得分:3)

您的选择似乎是:

a)与库的作者联系,并说明两个构造函数的行为方式不同的情况。也许他们可以为您解决问题。如果它是开源的,也许您可​​以自己修复它并提交请求请求。

b)初始化类时传递默认值:

var obj = new MyTest(1);

c)创建一个工厂方法,该方法可以将构造函数与可选值一起使用,但使用反射(较慢):

public static Test ConstructTest(int? i = null)
{
    // find the constructor that takes an `int`:
    ConstructorInfo constructorMethod = typeof(Test).GetConstructor(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance, null, new Type[] { typeof(int) }, null);
    if (constructorMethod == null)
    {
        throw new Exception("desired constructor not found"); // replace with specific exception
    }

    ParameterInfo iParameter = constructorMethod.GetParameters().Single();
    if (!i.HasValue && !iParameter.HasDefaultValue)
    {
        throw new Exception("no parameter specified, no default value"); // replace with specific exception
    }

    i = i ?? (int)iParameter.DefaultValue; // use the supplied parameter or the default value
    return (Test)constructorMethod.Invoke(new object[] { i }); // invoke the constructor
}

方法c)的风险是库可能会更改,然后您的代码将在运行时中断,而不是在编译时。如果您选择使用此选项,我强烈建议围绕这种情况编写一个单元测试,以便在每次更新第三方库时或发布之前进行验证。

答案 1 :(得分:1)

我不能代表原始开发人员的意图,但是有人可以实施此设计的最慈善原因是,您可以选择指定named parameters in C#。因此,在您的示例中,您可能会说:

var myClass = new MyClass(i: 1);

很明显,这不能为单个参数提供任何值,但是如果列表较长,则肯定具有一些优势:

public MyClass {
  public MyClass(int a=1, int b=2, int c=3 …) { }
}

那么您可以说:

new MyClass(c: 5);

这就是说,即使的意图(我不确定是),在这些情况下,更常见的模式是使用 options对象,或使用object initialization syntax指定属性的值:

var myClass = new MyClass {
  B = 5,
  H = 10
}

无论如何,我都同意这听起来像是一个考虑不周的设计,尤其是因为过载包含附加的设置逻辑。当然,这不是最佳实践。

这不是很漂亮,但是强制其使用重载的最佳方法是使用命名参数方法设置一个具有明显默认值的参数之一,例如null。这样,您将获得“正确的”重载,但无需指定所有值。

但是,除了包括至少一个参数外,没有一种(简单的方法)强制C#使用重载。

答案 2 :(得分:0)

当然,集体行为完全取决于其提供者,即您情况下的第三者。但是不要忽略它具有多个构造函数。您的提供者可能会对开发人员创建的毫无意义的开发人员造成彻底的灾难。但是通常一切都有目的。如果您的类具有多个构造函数,例如

public MyClass() {. . . }
public MyClass(int x) {. . . }

很有可能是一个属性X,它是可选的或具有默认值,您可以像这样设置它

public MyClass() {X = 5 }

但最重要的是-与您的供应商联系

但是,这还不是全部。有些类旨在以不同的方式完成相同的事情

public MyClass(DataTable dt) {. . . }
public MyClass(DataReader dr) {. . . }
public MyClass(IEnumerable<poco> modelList) {. . . }