Деконструкция неоднозначна
У меня есть векторный класс с двумя методами деконструкции следующим образом:
public readonly struct Vector2
{
public readonly double X, Y;
...
public void Deconstruct( out double x, out double y )
{
x = this.X;
y = this.Y;
}
public void Deconstruct( out Vector2 unitVector, out double length )
{
length = this.Length;
unitVector = this / length;
}
}
Где-то еще у меня есть:
Vector2 foo = ...
(Vector2 dir, double len) = foo;
Это дает мне:
CS0121: The call is ambiguous between the following methods or properties: 'Vector2.Deconstruct(out double, out double)' and 'Vector2.Deconstruct(out Vector2, out double)'
Как это неоднозначно?
Редактировать: вызов Deconstruct вручную работает нормально:
foo.Deconstruct( out Vector2 dir, out double len );
Ответы
Ответ 1
Это по замыслу в С#. Перегрузки Deconstruct должны иметь различную арность (количество параметров), в противном случае они неоднозначны.
Сопоставление с образцом не имеет левой стороны. Более сложная схема сопоставления с образцом состоит в том, чтобы иметь список сопоставляемых образцов в скобках, и мы используем количество шаблонов, чтобы решить, какой Deconstruct использовать. - Нил Гафтер https://github.com/dotnet/csharplang/issues/1998#issuecomment-438472660
Ответ 2
Быстрый отказ от ответственности - у меня нет С# 7.3, и я не видел этот шаблон раньше.
Тем не менее, я подозреваю, что это может сработать...
public readonly struct Vector2
{
public readonly double X, Y;
public DeconstructHelper<double, double> To_X_and_Y
{
get
{
return new DeconstructHelper<double, double>(
this.X
, this.Y
);
}
}
public DeconstructHelper<Vector2, double> To_Unit_and_Length
{
get
{
var length = this.Length;
return new DeconstructHelper<Vector2, double>(
length
, this / length
);
}
}
public class DeconstructHelper<T_Arg1, T_Arg2>
{
protected T_Arg1 Argument1 { get; private set; }
protected T_Arg2 Argument2 { get; private set; }
public DeconstructHelper(
T_Arg1 argument1
, T_Arg2 argument2
)
{
this.Argument1 = argument1;
this.Argument2 = argument2;
}
public void Deconstruct(
out T_Arg1 argument1
, out T_Arg2 argument2
)
{
argument1 = this.Argument1;
argument2 = this.Argument2;
}
}
}
Тогда, чтобы назвать это, было бы
var vector = new Vector2( /* ... */ );
(var x, var y) = vector.To_X_and_Y;
(var unitVector, var length) = vector.To_Unit_and_Length;
Общая идея получить get
-property для создания объекта с версией .Deconstruct()
вы хотите.