C#如何标记抽象class的属性不为空,因为在实现class构造函数时需要设置(CS8618)?
C# how to mark the property of the abstract class is not null because setting is required in implementing class constructor (CS8618)?
我有一个摘要 class 作为各种实现的基础 class。
让它看起来像这样:
public abstract class MyBase {
public object Property1 { get; protected set; }
}
重要的是,Property1
的类型是 object
而不是 object?
。
我希望完全清楚 Property1
在实现实例中永远不会为空。
假设典型的实现如下所示:
public sealed class MyImpl : MyBase {
public MyImpl() {
Property1 = new object();
}
}
当然,在现实世界中,基础 class 中有很多属性,而且它们的类型多种多样,而不仅仅是 object
。我可以将这些属性标记为 abstract
,但是我必须在每个实现 class 中实现它们——这意味着更多的样板代码并没有真正的好处,对吧?
好的,但现在我收到一条警告,在退出构造函数之前属性必须具有非空值 - CS8618。当然我可以为我的基础 class 禁用警告,但是是否有更优雅的方法来指示编译器实现 class 必须将这些属性设置为非空值而不是禁用警告?
如果我收到的警告不是针对基础 class,而是针对实现,如果它没有设置其中一个属性,那就完美了。
正如我已经发现的那样 - 最新的 C# 编译器和 Visual Studio 有很多神奇的特殊属性可以改变可为 null 的警告行为,但我不知道去哪里找。
It is important, that the type of Property1 is object and not object?. I want it to be completely clear that the Property1 is never null in implementation instance.
只有 方法可以保证 MyBase
中的 protected
构造函数需要 Property1
[=55= 的值] 或 通过使 Property1
成为 abstract
属性.
在 .NET 中,当子class 被实例化时,首先它的超类型的构造函数运行完成,然后是下一个子类型的构造函数,依此类推。目前在 .NET 中没有规定超类型有一个在 most-derived-type 的构造函数运行之后运行的“post-constructor”(我希望有……),所以没有办法MyBase
class 到 向编译器 证明 Property1
在构造对象时将处于有效状态。拥有 protected set
不是任何类型的可证明的保证(至少就编译器而言):它是 OOP 等同于 subclass 说“我 pinkie-swear 来设置它属性 在我的构造函数中!”你程序的其余部分必须信任那个口头承诺。
这就是自 C# 8.0 以来的可空注释如此重要且如此有用的原因:因为现在我们 no-longer 需要仅基于信任进行操作:我们现在可以让编译器 实际验证 field/auto-property 实际上分配给了 non-null 值,从而防止任何 NullReferenceException
( 每个人最喜欢的异常!)曾经被扔在第一位。
在这种情况下,非abstract
子class 是sealed
的事实对编译器来说无关紧要,因为您的MyBase
仍然可以单独派生一个永远不会设置 Property1
.
的行为不端的 subclass
Of course in real world there are plenty of properties in the base class and they are of various types, not just object
. I could mark the properties as abstract
, but then I would have to implement them in each implementing class - that would mean more boilerplate code with no real benefit in that, right?
我理解必须复制+粘贴或手动 keystroke-in 重复的成员很烦人,但如果(重新)实现这些 abstract
成员表达了一些有意义的东西,那么这样做不是“样板”你的 business/domain 模型。
I get a warning that the properties must have non-null values before exiting constructor - CS8618. Of course I can disable the warning for my base class, but is there a more elegant way to instruct the compiler that the implementing class MUST set those properties to non-null values instead of disabling the warning?
只需使用 protected
构造函数。这正是他们的目的。
像这样:
public abstract class MyBase
{
protected MyBase(object property1Value)
{
this.Property1 = property1Value ?? throw new ArgumentNullException(nameof(property1Value));
}
public object Property1 { get; }
}
这样所有子classes 都是安全的:
public sealed class Derived : MyBase
{
public Derived()
: base( GetProperty1FromAStaticFactory() )
{
}
}
或
public sealed class Derived : MyBase
{
public Derived( Object p1Value )
: base( p1Value )
{
}
}
我有一个摘要 class 作为各种实现的基础 class。
让它看起来像这样:
public abstract class MyBase {
public object Property1 { get; protected set; }
}
重要的是,Property1
的类型是 object
而不是 object?
。
我希望完全清楚 Property1
在实现实例中永远不会为空。
假设典型的实现如下所示:
public sealed class MyImpl : MyBase {
public MyImpl() {
Property1 = new object();
}
}
当然,在现实世界中,基础 class 中有很多属性,而且它们的类型多种多样,而不仅仅是 object
。我可以将这些属性标记为 abstract
,但是我必须在每个实现 class 中实现它们——这意味着更多的样板代码并没有真正的好处,对吧?
好的,但现在我收到一条警告,在退出构造函数之前属性必须具有非空值 - CS8618。当然我可以为我的基础 class 禁用警告,但是是否有更优雅的方法来指示编译器实现 class 必须将这些属性设置为非空值而不是禁用警告?
如果我收到的警告不是针对基础 class,而是针对实现,如果它没有设置其中一个属性,那就完美了。
正如我已经发现的那样 - 最新的 C# 编译器和 Visual Studio 有很多神奇的特殊属性可以改变可为 null 的警告行为,但我不知道去哪里找。
It is important, that the type of Property1 is object and not object?. I want it to be completely clear that the Property1 is never null in implementation instance.
只有 方法可以保证 MyBase
中的 protected
构造函数需要 Property1
[=55= 的值] 或 通过使 Property1
成为 abstract
属性.
在 .NET 中,当子class 被实例化时,首先它的超类型的构造函数运行完成,然后是下一个子类型的构造函数,依此类推。目前在 .NET 中没有规定超类型有一个在 most-derived-type 的构造函数运行之后运行的“post-constructor”(我希望有……),所以没有办法MyBase
class 到 向编译器 证明 Property1
在构造对象时将处于有效状态。拥有 protected set
不是任何类型的可证明的保证(至少就编译器而言):它是 OOP 等同于 subclass 说“我 pinkie-swear 来设置它属性 在我的构造函数中!”你程序的其余部分必须信任那个口头承诺。
这就是自 C# 8.0 以来的可空注释如此重要且如此有用的原因:因为现在我们 no-longer 需要仅基于信任进行操作:我们现在可以让编译器 实际验证 field/auto-property 实际上分配给了 non-null 值,从而防止任何 NullReferenceException
( 每个人最喜欢的异常!)曾经被扔在第一位。
在这种情况下,非abstract
子class 是sealed
的事实对编译器来说无关紧要,因为您的MyBase
仍然可以单独派生一个永远不会设置 Property1
.
Of course in real world there are plenty of properties in the base class and they are of various types, not just
object
. I could mark the properties asabstract
, but then I would have to implement them in each implementing class - that would mean more boilerplate code with no real benefit in that, right?
我理解必须复制+粘贴或手动 keystroke-in 重复的成员很烦人,但如果(重新)实现这些 abstract
成员表达了一些有意义的东西,那么这样做不是“样板”你的 business/domain 模型。
I get a warning that the properties must have non-null values before exiting constructor - CS8618. Of course I can disable the warning for my base class, but is there a more elegant way to instruct the compiler that the implementing class MUST set those properties to non-null values instead of disabling the warning?
只需使用 protected
构造函数。这正是他们的目的。
像这样:
public abstract class MyBase
{
protected MyBase(object property1Value)
{
this.Property1 = property1Value ?? throw new ArgumentNullException(nameof(property1Value));
}
public object Property1 { get; }
}
这样所有子classes 都是安全的:
public sealed class Derived : MyBase
{
public Derived()
: base( GetProperty1FromAStaticFactory() )
{
}
}
或
public sealed class Derived : MyBase
{
public Derived( Object p1Value )
: base( p1Value )
{
}
}