需要参数命名以防止在相同的参数列表上出现歧义

时间:2013-11-18 15:23:15

标签: c# oop arguments ambiguous

考虑以下定义:

class Foo
{
    string Asd;
    List<int> Qwert;

    public Foo(string Bar, List<int> Baz = null)
    {
        // Set up instance from parameters
        this.Asd = Bar;
        this.Qwert = Baz ?? new List<int>;
    }

    public Foo(string Qwop)
    {
        // Code which sets up the instance based on what Qwop is
        // E.g.: take Asd and Qwert values from a previous storage
    }
}

现在,如果我将构造函数调用为Foo foo = new Foo("value");,则执行第二个构造函数。

如何让编译器强制使用命名参数进行调用?因为两个建设者都是&#39;第一个参数是string,有明显的模糊性。 (无论如何,我无法逃避或解决这个问题,我们需要采用string。)

Foo foo = new Foo("value"); // NOT fine
Foo foo = new Foo(Bar: "value"); // Fine, first constructor
Foo foo = new Foo("value", new List<int> { 0, 1, 2 }; // Fine, as it is clearly 1st
Foo foo = new Foo(Qwop: "anothervalue"); // Fine, second constructor

我考虑过声明一个额外的构造函数:

[Obsolete("Parameterization would be ambiguos. Please specify what string is by using named parameters", true)]
public Foo(string param)
{
    throw new ArgumentException();
}

我认为这意味着如果没有命名参数,代码会调用此代码并且编译将失败。但是之前的构建失败了,因为

  

键入&#39; Program.Foo&#39;已经定义了一个名为&#39; Foo&#39;使用相同的参数类型

显然,这是不行的。但我的另一个尝试:

class Foo
{
    public Foo(IFooInvoker invoker)
    {
        if (invoker is FooInvokerBarBaz) { ... }
        else if (invoker is FooInvokerQwop) { ... }
    }
}

interface IFooInvoker { ... }

class FooInvokerBarBaz : IFooInvoker { ... }
class FooInvokerQwop : IFooInvoker { ... }

// And calling the whole from Main by
Foo foo = new Foo(new FooInvokerBarBaz("bar", new List<int> { 0, 1, 2 });
// or
Foo foo = new Foo(new FooInvokerQwop("qwop");

看起来方式过于复杂,丑陋而且我认为违反了多项设计原则。

2 个答案:

答案 0 :(得分:5)

  

如何让编译器强制使用命名参数进行调用?

基本上,你不能。它只是语言的一部分。

可以做的是使构造函数变为私有,而是公开静态工厂方法,这些方法解释了它们构造实例的内容。

public static Foo FromBarAndBaz(string bar, List<int> baz = null)
{
    return new Foo(bar, baz);
}

public static Foo FromQwop(string qwop)
{
    return new Foo(qwop);
}

(为简单起见,您可能也希望在构造函数中强制baz。)

请注意,我已更改参数名称以符合正常的.NET命名约定。

答案 1 :(得分:1)

不,你不能。 C#只是不支持它。你可以使你的签名不那么相似,例如。

public Foo(string bar, List<int> baz) // baz is now required, but can be null
public Foo(string qwop)

或者您可以将构造函数设为私有并公开静态方法:

private Foo(string bar, List<int> baz)
private Foo(string qwop)
public static Foo FromBarBaz(string bar, List<int> baz = null)
public static Foo FromQwop(string qwop)

(作为次要注释,参数should be camelCased,而不是PascalCased)

相关问题