Conditionally set properties in object initializers #5588
Replies: 7 comments 33 replies
-
Definitely seems like an interesting case. i presume the following are not viable: var readB = reader.TryReadInt32("B", out int b);
var c = reader.ReadInt32("C");;
A a = readB ? new A { B = b, C = c } : new A { C =c }; Presumably this would be bad because of combinatorics. Alternatively, could you make a A a = new A {
B = reader.TryReadInt32("B", out int v) ? v : s_defaultA.B,
C = reader.ReadInt32("C"),
}; This also seems unpleasant (and quite possibly unsafe if there's shared mutable data?). But i'm just spitballing ideas to see if there's something possible that's palatable. If not, then it does seem like we might need something here. |
Beta Was this translation helpful? Give feedback.
-
What about allowing if statement in initialization block A a = new A {
if(reader.TryReadInt32("B", out int v))
B = v,
C = reader.ReadInt32("C"),
}; |
Beta Was this translation helpful? Give feedback.
-
A different solution would be to allow setting init properties until the value is first read. Then you could do: A a = new A {
C = reader.ReadInt32("C"),
};
if (reader.TryReadInt32("B", out int v))
{
a.B = v,
} But this would be illegal: A a = new A {
C = reader.ReadInt32("C"),
};
Use(a);
if (reader.TryReadInt32("B", out int v))
{
a.B = v,
} |
Beta Was this translation helpful? Give feedback.
-
Another need I sometimes face: var c = new Class
{
A = 123,
B = init.A + 10,
}; Here, I invented a keyword (similarly to OP's var res =
query
.Select(p=>new
{
FullName = p.FirstName + " " + p.LastName,
FullNameAndSuffix = init.FullName + " " + p.Suffix
}); If we were to add this keyword, then OP scenario becomes possible: var c = new Class
{
A = int.TryParse(str, out a) ? a : init.A,
}; Basically, I think we can kill a few birds with one stone. I'm not stuck on |
Beta Was this translation helpful? Give feedback.
-
It looks like System.Text.Json now could benefit from this as well with its source generator. Currently, they simply cannot support |
Beta Was this translation helpful? Give feedback.
-
It feels like if we do something for object initializers here, there should be space to expand it to other kinds of initializers and literals in the future, if desired. _ = new Widget { Prop = value when (cond) };
_ = new Collection { A, B, C when(cond) };
_ = [A, B, C when(cond)];
_ = new[] { A, B, C when(cond) } |
Beta Was this translation helpful? Give feedback.
-
This could be a good use case for Lazy Initialized auto properties: #7145 |
Beta Was this translation helpful? Give feedback.
-
In MessagePack-CSharp/MessagePack-CSharp#1369 (comment) we discuss how it seems to be impossible to initialize an object's
init
properties conditionally. For a deserializer that needs to set these properties iff values for those properties appear in the serialized data stream, this presents a real problem for AOT generated deserializer code. I expect the System.Text.Json deserializer's new AOT code gen feature in 6.0.0 may suffer from the same problem.For example consider initializing this object:
Properties B and C can only be set with syntax like this:
This is fine for hand-written code. But for an AOT code generated deserializer when values for B or C are optional, we would need something like this:
But how would we make the assignments to B (and C) optional such that a missing value for B would allow the
3
default value to remain? I know of no way to conditionally call aninit
accessor. An alternative might be to invoke it with its existing value, but as there is no way to reference the object within its own object initializer, we can't do something like this:Above I hypothesize that
_
is a reference to the initializing object, but this isn't valid C# 10 code.Do we need a new feature for this?
Beta Was this translation helpful? Give feedback.
All reactions