Компилятор не различает конструктор по умолчанию и конструктор с ключевым словом params
Суть проблемы заключается в том, что если я создаю объект Progression с пустыми скобками в конце, объект создается по конструктору (params float[]), вместо выдачи ошибки, несмотря на то что конструктор по умолчанию я сделал приватным.
class Progression
{
public float FirstElement { get; }
public float Difference { get; }
private Progression()
{
}
public Progression (float firstEl, float d)
{
FirstElement = firstEl;
Difference = d;
}
public Progression (float firstEl, (float, int) randomEl)
{
FirstElement = firstEl;
Difference = (randomEl.Item1 - firstEl) / (randomEl.Item2 - 1);
}
public Progression (Func<int, float> formula)
{
FirstElement = formula(1);
Difference = formula(2) - formula(1);
}
public Progression (params float[] element)
{
FirstElement = element[0];
Difference = element[1] - element[0];
}
}
Ответы (1 шт):
Так работает params: пустой массив является частным случаем массива. Поэтому ваш вызов не может быть обслужен приватным конструктором (потому что он приватный), но может быть обслужен конструктором с params.
Если вы хотите, чтобы хотя бы один параметр в params был обязательным, вынесите его из params:
public Progression(float firstEl, params float[] restElements)
{
FirstElement = firstEl;
Difference = restElements[0] - firstEl;
}
Кстати, у вас и так есть конструктор с двумя float-аргументами, так что вызов new Progression(1f, 1f) вызовет конструктор Progression(float firstEl, float d), а не Progression(float firstEl, params float[] restElements). Это явно не то, что вам нужно, т. к. второй элемент будет проинтерпретирован не как член последовательности, а как разность.
А вот вызов конструктора с одним аргументом снова приведёт к пустому массиву и падению на restElements[0]. Так что вам по сути нужно два обязательных параметра.
Лучше воспользоваться идиомой «именованный конструктор»:
class Progression
{
public float FirstElement { get; }
public float Difference { get; }
private Progression(float firstEl, float d)
{
FirstElement = firstEl;
Difference = d;
}
static public Progression FromStartAndDiff(float start, float diff)
{
return new Progression(start, diff);
}
static public Progression FromFormula(Func<int, float> formula)
{
return new Progression(formula(1), formula(2) - formula(1));
}
static public Progression FromElements(float firstEl, float secondEl)
{
return new Progression(firstEl, secondEl - firstEl);
}
}
При этом вы можете создавать объект так:
var p1 = Progression.FromStartAndDiff(1, 2);
var p2 = Progression.FromFormula(n => 2 * n - 1);
var p3 = Progression.FromElements(1, 3);