Replies: 9 comments 70 replies
-
While I probably agree that at least a warning should be standard fare for the V2 version of the class, whether that is provided by the compiler or an analyzer that is on by default doesn't seem to be a big difference. It's always going to be incumbent on ORMs, deserializers or other tools based on reflection to respect the metadata, as it already is with |
Beta Was this translation helpful? Give feedback.
-
If you are concerned about this class of bugs, then writing an analyzer for your domain needs seems reasonable.
All features only work some of the time. All of them have limitations and ways you can still have some classes of bugs. That's why things like analyzers exist. And that's why we still need to write tests. |
Beta Was this translation helpful? Give feedback.
-
I would second the concern raised in the OP. I was under the impression this whole time that this attribute triggers a requirement that the required members are set. I'm extremely surprised by the fact that it does not. Regarding writing a custom analyzer, this may or may not be a realistic expectation. If the Roslyn API that analyzers can utilize provides a helper to determine things like "look for stuff done under all possible control flows", then yes, it becomes straightforward to enforce that members are assigned. Otherwise, an analyzer author has to essentially re-write the code which the C# compiler already has to traverse all the possible control flows; this quickly becomes much more complicated. WRT language design, I cannot think of any scenarios where it may be desirable to decorate the ctor with the attribute, and not fulfill that promise; this leads me to think that it should indeed be a warning, if not an error, in the language, and not an optional analyzer. |
Beta Was this translation helpful? Give feedback.
-
This is not true. You can trivially make a method that uses |
Beta Was this translation helpful? Give feedback.
-
I'm sympathetic about the difficulty around
class C
{
[SetsRequiredMembers]
public C()
{
Helper();
}
public void Helper()
{
X = 42;
}
public required int X { get; set; }
} It's possible that it might be more useful to give a warning in the above scenario to the effect of hey, we don't know if you set FWIW, we've also adjusted nullable analysis slightly here to provide a guardrail specifically when non-nullable reference types are in use. #nullable enable
using System.Diagnostics.CodeAnalysis;
class C
{
public C() // no warning
{
}
[SetsRequiredMembers]
public C(bool unused) // warning CS8618: Non-nullable property 'X' must contain a non-null value when exiting constructor.
{
}
public required string X { get; set; }
} |
Beta Was this translation helpful? Give feedback.
-
Analyzers lag behind language features. If Roslyn had an analyzer that gave you what you want today, what would it do? What would it look like? What would the attribute name be? Would it be useful if static analysis did not reach beyond the ctor's of the current class (we may not have access to the base)? |
Beta Was this translation helpful? Give feedback.
-
Im also concerned that this feature isnt properly enforced in all scenarios. If it is going to stay like that (and i expect them to stay that way forever due to several impossibilities outlined in that blogs comments) then |
Beta Was this translation helpful? Give feedback.
-
We don't expect any form of inter-procedural analysis. But at least this should work: var foo = new Foo(42);
class Foo
{
public required int Bar { get; init; }
public Foo(int bar)
{
Bar = bar;
}
} So that we can have the option to not use the The In other words, the current required members feature is half baked and doesn't play well with constructors at all. |
Beta Was this translation helpful? Give feedback.
-
I would like to add one more example of var a = new A { PropA = "A" };
var b = new B(a) { PropB = "B" };
var b1 = new B(a); // no warning
class A
{
public required string PropA { get; init; }
[SetsRequiredMembers]
public A(A a) => PropA = a.PropA;
public A(){}
}
[method: SetsRequiredMembers]
class B(A a) : A(a)
{
public required string PropB { get; init; } // warning CS8618: Non-nullable property 'PropB' must contain a non-null value
} Sharplab link It would be ideal to make this code work: var a = new A { PropA = "A" };
var b = new B(a) { PropB = "B" }; // Error CS 9035
class A
{
public required string PropA { get; init; }
[SetsRequiredMembers]
public A(A a) => PropA = a.PropA;
public A() { }
}
class B(A a) : A(a) // Error CS 9039
{
public required string PropB { get; init; }
} Sharplab link |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
In the recent blog post announcing the
required
members feature- a number of the comments make the same point about the brittle nature of the[SetsRequiredMembers]
attribute the C# team has settled on. The fact that checking a constructor sets all required members is entirely developer-dependent and lacks any static analysis backing it up seems to be an obvious pit of failure that will result in a common source of bugs for anyone relying on this feature.To summarize the problem briefly:
V1:
V2 - Boss wants us to add a new property "Baz"
Although this example is trivial because the property declarations are right next to the constructor- they need not be. They could be 2000 lines away from each other, in a totally separate file, or even a totally separate class we're inheriting from and don't have the source code from.
In short, I think it would be a huge mistake to ship this feature in such a state. It is repeating the same problem nullability tracking has- that it's really more of a suggestion than anything concrete that can be relied upon at runtime.
If
required
cannot be enforced absolutely by the compiler or runtime the feature should be scrapped. Not only can it lead to the bugs shown above, but just imagine if tools like ORMs or client generators try to integraterequired
ness into code generation. You end up propagating the potential bugs up and down the tech stack. A feature that works well only some of the time in simple scenarios is worse than no feature at all.Beta Was this translation helpful? Give feedback.
All reactions