2012-02-24 3 views
2

Предположим, например, я определяю класс Complex для представления комплексных чисел. Я хотел бы определить два конструктора, так что я могу написать, например:C#: методы и конструкторы одинаковой подписи и именованные аргументы

Complex z1 = new Complex(x: 4, y: 3); 
Complex z2 = new Complex(r: 2, theta: Math.PI/4); 

Однако, я не могу определить конструктор, как это:

public Complex(double x, double y) { ... } 
public Complex(double r, double theta) { ... } 

, потому что оба конструкторы будут иметь ту же подпись, которая не допускается. Но в C# 4, я могу написать это, используя дополнительный аргумент:

public Complex(double x, double y) { ... } 
public Complex(double r, double theta, bool unused=true) { ... } 

Он работает, я могу затем использовать вышеуказанные вызовы конструктора по назначению. Единственная цель аргумента unused - сделать разные подписи; он полностью не используется, как при определении, так и при вызове конструктора.

Мне кажется, что это уродливый трюк: есть ли лучший вариант?

+1

На самом деле вы ничего не покупаете - у вас нет контроля над тем, что вы вызываете с двумя двойными аргументами (он всегда будет одним и тем же). –

+0

Вы правы, но моя цель - явно выбрать, какой конструктор я хочу использовать, используя именованные аргументы. – ChrisJ

ответ

7

Сделать конструктор закрытым и иметь статическую фабричную функцию стиля.

public static Complex CreateComplexPolar(double r, double theta); 
public static Complex CreateComplex(double x, double y); 

Вы можете сделать валидацию на входах на основе того, что они должны быть.

Другой возможностью было бы создание типа, который инкапсулирует входы и использует конструкторы, как вы упомянули ранее.

public struct PolarCoordinates 
{ 
    public double Rho; 
    public double Theta; 
} 

public struct CartesianCoordinates 
{ 
    public double X; 
    public double Y; 
} 

public Complex(PolarCoordinates pc); 
public Complex(CartesianCoordinates cc); 
3

Создать статический метод для создания класса, скажем Complex::FromDouble и Complex::FromDoubleAndTheta.

Вы можете сделать еще один шаг и сделать реальный конструктор частным, чтобы заставить эту конструкцию.

Например, см. TimeSpan's FromDays и FromHours.

p.s. лучше использовать имена :)

HTH

0

Единственное, что я могу думать о том, чтобы сделать один конструктор (двойной, двойной), а другой может быть двойной, Func.

public Complex(double x, double y) { ... } 
public Complex(double r, Func<double> theta) { ... } 

Похоже, в вашем примере сверху, что вы делаете расчет и результат этого расчета является вторым значением для этого конструктора. Если это всегда так, тогда вы можете просто указать параметр Func. Вид взлома, но это может быть лучше, чем наличие необязательного третьего параметра, который ничего не делает.

+0

Собственно, 'theta' - это всего лишь угол. π/4 на самом деле не является * вычислением *, просто удобным способом задания значения угла. Я мог бы написать что-то вроде '0.79'. Поэтому второй аргумент должен быть двойным. – ChrisJ

+0

Я вижу вашу точку зрения. Хотя вы все равно можете использовать его таким образом, чтобы дифференцировать конструкторы. Тем не менее, взломать.Задумывались ли вы о безпараметрическом конструкторе, а затем использовали свойства для различных комбинаций параметров? Либо это, либо я предполагаю, что вы можете сделать базовый класс и сделать каждый конструктор отдельным классом, который наследуется от базы. –

+0

Свойства конструктора без параметров: меня беспокоит то, что вы можете создать «неинициализированный» объект. Подкласс: класс должен представлять * вид объектов *, а не * тип конструктора * ... Так что снова это хак ... – ChrisJ

Смежные вопросы