Reputation: 2301
To access ValueTuple members, I would do
public Plane Init (ValueTuple<Vector4D, Vector4D, Vector4D, Vector4D> vertices)
{
Vector4D[] m_vertices = new Vector4D [4];
m_vertices[0] = vertices.Item1;
// etc
return this;
}
Can I use a nullable ValueTuple argument, and how would I access its members? Here's what I tried, and it doesn't work:
public Plane Init (ValueTuple<Vector4D, Vector4D, Vector4D, Vector4D>? vertices = null)
{
Vector4D[] m_vertices = new Vector4D [4];
// not working
m_vertices[0] = vertices ?? vertices.Item1 : CVector4D (0,0,0,0);
// not working either
m_vertices[0] = vertices ?? vertices?.Item1 : CVector4D (0,0,0,0);
// etc
return this;
}
Upvotes: 0
Views: 429
Reputation: 112259
By using the concise C# syntax for ValueTuple types and values, we can write:
static readonly Vector4D Origin4D = new Vector4D(0, 0, 0, 0);
public Plane Init((Vector4D, Vector4D, Vector4D, Vector4D)? vertices)
{
var v = vertices ?? (Origin4D, Origin4D, Origin4D, Origin4D);
var m_vertices = new Vector4D[] { v.Item1, v.Item2, v.Item3, v.Item4 };
// etc
return this;
}
If you are in control of Vector4D
it is a good idea to add it a static member
public static Vector4D Origin { get; } = new Vector4D(0, 0, 0, 0);
You can then access it with Vector4D.Origin
.
If you need a variable number of parameters, use a params parameter:
public Plane Init(params Vector4D[] vertices)
{
Vector4D[] m_vertices = vertices;
}
Upvotes: 1
Reputation: 1062492
In the case where the null
scenario would give the zero-default equivalent (if we assume that CVector4D
is a struct
), then there is a cheat you can use to simplify this code:
public Plane Init (ValueTuple<CVector4D, CVector4D, CVector4D, CVector4D>? vertices = null)
{
var val = vertices.GetValueOrDefault();
m_vertices = new[] { val.Item1, val.Item2, val.Item3, val.Item4 };
// ...
}
This works because GetValueOrDefault()
will return the inner T
value of the T?
if there is a value, and the default(T)
otherwise; and in this case: default(T)
will be the all-zero case that you wanted. So: all done.
But: you can probably simplify a bit more, and lose the T?
:
public Plane Init (ValueTuple<CVector4D, CVector4D, CVector4D, CVector4D> vertices = default)
{
m_vertices = new[] { vertices.Item1, vertices.Item2, vertices.Item3, vertices.Item4 };
// ...
}
That said: it may be clearer to pass in the vectors individually rather than as a value-tuple, i.e.
public Plane Init (CVector4D vertex0, CVector4D vertex1, CVector4D vertex2, CVector4D vertex3)
{
m_vertices = new[] { vertex0, vertex1, vertex2, vertex3 };
// ...
}
Upvotes: 0
Reputation: 8359
To access an item for a Nullable<ValueTuple<>>
you should use the Null-conditional operators ?.
operator, and the null-coalescing operator ??
to provide a value in case of a null
:
var v1 = vertices?.Item1 ?? fallBackValue;
But to avoid multiple redundant null
test, you should use a default value for the tuple if it is null
:
private static Vector4D ZeroVector4D { get; } = new Vector4D();
private static (Vector4D, Vector4D, Vector4D, Vector4D) DefaultVertices { get; } = (ZeroVector4D, ZeroVector4D, ZeroVector4D, ZeroVector4D);
public Plane Init(ValueTuple<Vector4D, Vector4D, Vector4D, Vector4D>? vertices = null)
{
return Init(vertices ?? DefaultVertices);
}
public Plane Init(ValueTuple<Vector4D, Vector4D, Vector4D, Vector4D> vertices)
{
m_vertices[0] = v.Item1;
m_vertices[1] = v.Item2;
m_vertices[2] = v.Item3;
m_vertices[3] = v.Item4;
return this;
}
You can also use some pattern matching :
var m_vertices = new Vector4D[4];
if (vertices is (Vector4D a, Vector4D b, Vector4D c, Vector4D d))
{
m_vertices[0] = a;
m_vertices[1] = b;
m_vertices[2] = c;
m_vertices[3] = d;
}
Upvotes: 1
Reputation: 2301
I found a solution that comes closest to what I want:
public Plane Init (ValueTuple<CVector4D, CVector4D, CVector4D, CVector4D>? vertices = null)
{
CVector4D[] m_vertices;
m_vertices = new Vector4D[4];
// the elements of m_vertices are default initialized as intended already here
if (vertices != null)
{
m_vertices[0] = vertices?.Item1;
m_vertices[1] = vertices?.Item2;
m_vertices[2] = vertices?.Item3;
m_vertices[3] = vertices?.Item4;
}
return this;
}
It is just a little guesswork and a heck of a lot of googling to find out how to write this down.
Btw,
m_vertices[0] = vertices?.Item1 ?? vertices?.Item1 : new Vector4D (0,0,0,0);
Does not work; Instead of ":", I get an error that ";" or "}" are expected.
Simply writing
m_vertices[0] = vertices.Item1;
after the "if (vertices != null)" statement yields an error as well: (Vector4D, Vector4D, Vector4D, Vector4D) does not contain a definition for 'Item1' and no accessible extension method 'Item1' accepting a first argument of type '(Vector4D, Vector4D, Vector4D, Vector4D)' could be found.
Using target system ".NET Framework 4.7.2".
With the hint of Orace below, this is probably the (or a) right way to do it:
public Plane Init (ValueTuple<CVector4D, CVector4D, CVector4D, CVector4D>? vertices = null)
{
CVector4D[] m_vertices;
m_vertices = new Vector4D[4];
// the elements of m_vertices are default initialized as intended already here
if (vertices != null)
{
m_vertices[0] = vertices.Values.Item1;
m_vertices[1] = vertices.Values.Item2;
m_vertices[2] = vertices.Values.Item3;
m_vertices[3] = vertices.Values.Item4;
}
return this;
}
Upvotes: 0