#c# #constructor #default-arguments
Вопрос:
В C я могу сделать что-то вроде
class CVector3D { public: float x, y, z; CVector3D (float x = 0.0f, float y = 0.0f, float z = 0.0f) : x(x), y(y), z(z) {} CVector3D (CVector3D constamp; other) { x = other.x, y = other.y, z = other.z; } }; class CMatrix3D { public: CVector3D r, u, f; CMatrix (r = CVector3D (1.0f, 0.0f, 0.0f), u = CVector3D (0.0f, 1.0f, 0.0f), f = CVector3D (0.0f, 0.0f, 1.0f)) : r(r), u(u), f(f) {} };
В C# я попытался:
public class CVector3D { public (float x, float y, float z) coords; public CVector3D (float x = 0.0f, float y = 0.0f, float z = 0.0f) =gt; coords = (x,y,z); } public class CMatrix3D { public (CVector3D r, CVector3D u, CVector3D f) dirs; // variant 1.1 public CMatrix3D (CVector3D r = CVector3D (1.0f, 0.0f, 0.0f), CVector3D u = CVector3D (0.0f, 1.0f, 0.0f), CVector3D f = CVector3D (0.0f, 0.0f, 1.0f)) { dirs.r = r; dirs.u = u; dirs.f = f; } // variant 1.2 public CMatrix3D (CVector3D r = new CVector3D (1.0f, 0.0f, 0.0f), CVector3D u = new CVector3D (0.0f, 1.0f, 0.0f), CVector3D f = new CVector3D (0.0f, 0.0f, 1.0f)) { dirs.r = r; dirs.u = u; dirs.f = f; } // variant 2 public CMatrix( ValueTuplelt;float, float, floatgt; r = (1.0f, 0.0f, 0.0f), ValueTuplelt;float, float, floatgt; u = (0.0f, 1.0f, 0.0f), ValueTuplelt;float, float, floatgt; f = (0.0f, 0.0f, 1.0f)) { dirs.r = r; dirs.u = u; dirs.f = f; } }
Ни то, ни другое не работает. Я знаю, что мне нужно было бы сделать что-то вроде
Как бы я поступил, если бы хотел?
Комментарии:
1. Как я вижу, нет особого смысла указывать некоторые из этих параметров и оставлять другие «по умолчанию» (поэтому укажите только
r
иu
и оставьтеf
значение по умолчанию). Поэтому я бы просто добавил пустой конструктор, который приведет к матрице идентификаторов (или использовал для этого отдельное статическое свойство), и удалил все значения по умолчанию из текущего конструктора.2. Верно и очень хорошо подмечено. Я просто пытаюсь понять обработку аргументов по умолчанию в C#. Кажется намного сложнее, чем в C .
Ответ №1:
Как говорит компилятор: значения по умолчанию должны быть выражены как константы времени компиляции, что: это не так. Вы можете использовать null
значения, чтобы подразумевать эти значения, т. е.
public CMatrix3D(CVector3D r = null, CVector3D u = null, CVector3D f = null); { dirs.r = r ?? new CVector3D(1.0f, 0.0f, 0.0f); dirs.u = u ?? new CVector3D(0.0f, 1.0f, 0.0f); dirs.f = f ?? new CVector3D(0.0f, 0.0f, 1.0f); }
Однако я бы сказал, что на самом деле это простой случай для a readonly struct
(для обоих типов), а не class
. Тогда у меня, вероятно, было бы просто статическое Identity
свойство, которое возвращает идентификационную матрицу. Я также, вероятно ValueTuple
, вообще не стал бы здесь использовать.
Пример того, что я имею в виду (примечание: использует функции C# 10):
using System; var original = Matrix3D.Identity; Console.WriteLine(original); // show manipulation (note: you could also update the original value like this) var delta = original with { F = new (2,2,2)}; Console.WriteLine(delta); // to show tuple decomposition Console.WriteLine(delta.F); // uses our type's ToString var (r, u, f) = delta.F; Console.WriteLine($"r={r}, u={u}, f={f}"); // do it ourselves // record structs are C# 10, note! readonly record struct Vector3D(float X, float Y, float Z) { public static Vector3D Zero =gt; new(); public override string ToString() =gt; $"({X}, {Y}, {Z})"; } readonly record struct Matrix3D(Vector3D R, Vector3D U, Vector3D F) { public static Matrix3D Zero { get; } = new(); public static Matrix3D Identity { get; } = new(new(1, 0, 0), new(0, 1, 0), new(0, 0, 1)); public override string ToString() =gt; $"[{R}, {U}, {F}]"; }
Комментарии:
1. Спасибо, Марк. Не возражаете добавить пример кода для решения структуры только для чтения? Я хочу использовать значение, потому что векторные и матричные координаты должны быть изменяемыми.
2. @Razzupaltuff да, работаю над этим; Я бы сказал, математически, что вектор / матрица абсолютно не изменчивы, точно так же, как целое число, комплексное число, кватернион и т. Д. Не изменчивы. Возможно, вы захотите иметь возможность преобразовывать одну матрицу/вектор в другую, но это не одно и то же.
3. @Razzupaltuff также: с операторами композиции/декомпозиции: вам не нужна отдельная поддержка кортежей значений; вектор может действовать как кортеж.
4. Я исхожу из C , поэтому мне, возможно, придется приспособить свое мышление к другому мышлению для C#. Предположим, у меня есть вектор положения в каком-то объекте в 3D-игре. В C , чтобы изменить положение, я перезаписываю старые значения в векторе положения объекта. Так что этот вектор должен быть изменчивым. То же самое верно и для матрицы ориентации: когда меняется заголовок объекта, я хочу изменить его матрицу ориентации на месте.
5. @Razzupaltuff это зависит от вас — я покажу свой пример с
readonly
— вы можете удалить это