Skip to content

NET-1348 Modify S1699: Add How to fix it section #4977

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 28, 2025
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 128 additions & 11 deletions rules/S1699/csharp/rule.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,20 @@ For example:

[source,csharp]
----
public class Parent
public class Parent
{
public Parent()
public Parent()
{
DoSomething(); // Noncompliant
}

public virtual void DoSomething() // can be overridden
{
...
{
// ...
}
}

public class Child : Parent
public class Child : Parent
{
private string foo;

Expand All @@ -32,7 +32,7 @@ public class Child : Parent
this.foo = foo;
}

public override void DoSomething()
public override void DoSomething()
{
Console.WriteLine(this.foo.Length);
}
Expand All @@ -43,13 +43,130 @@ public class Child : Parent
* The `Parent` class constructor calls the method `DoSomething`, which has been overridden in the `Child` class.
* If the behavior of the `Child` class overridden `DoSomething` method depends on fields that are initialized in the `Child` class constructor, unexpected behavior (such as a `NullReferenceException`) can result, because the fields aren't initialized yet.

== How to fix it

Depending on the context, you can either:
* avoid calling overridable methods from constructors. This is the recommended approach
* ensure that the method is not overridden in any derived classes. This can be done by marking the method as `sealed` in the current class
* ensure that the class is not inherited from. This can be done by marking the class as `sealed`

=== Code examples

==== Noncompliant code

[source,csharp,diff-id=1,diff-type=noncompliant]
----
class Parent
{
public virtual void DoSomething() { }
}

class Child : Parent
{
public Child(string foo)
{
DoSomething(); // Noncompliant
}
}
----

[source,csharp,diff-id=2,diff-type=noncompliant]
----
class Parent
{
public virtual void DoSomething() { }
}

class Child : Parent
{
public Child(string foo)
{
DoSomething(); // Noncompliant
}
}
----

[source,csharp,diff-id=3,diff-type=noncompliant]
----
class Parent
{
public virtual void DoSomething() { }
}

class Child : Parent
{
public Child(string foo)
{
DoSomething(); // Noncompliant
}
}
----

==== Compliant solution

[source,csharp,diff-id=1,diff-type=compliant]
----
class Parent
{
public virtual void DoSomething() { }
}

class Child : Parent
{
public Child(string foo)
{
}
}
----

[source,csharp,diff-id=2,diff-type=compliant]
----
class Parent
{
public virtual void DoSomething() { }
}

class Child : Parent
{
public Child(string foo)
{
DoSomething();
}

public sealed override void DoSomething()
{
base.DoSomething();
}
}
----

[source,csharp,diff-id=3,diff-type=compliant]
----
class Parent
{
public virtual void DoSomething() { }
}

sealed class Child : Parent
{
public Child(string foo)
{
DoSomething();
}
}
----



== Resources

=== Documentation

* https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/constructors[Constructors]
* https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/object-oriented/inheritance[Inheritance]
* https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/object-oriented/polymorphism#virtual-methods[Polimorphism]
* https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/methods#method-signatures[Method signatures]
* Microsoft Learn - https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/constructors[Constructors]
* Microsoft Learn - https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/object-oriented/inheritance[Inheritance]
* Microsoft Learn - https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/object-oriented/polymorphism[Polimorphism]
* Microsoft Learn - https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/methods#method-signatures[Methods - Method signatures]
* Stack Overflow - Answer by Eric Lippert for https://stackoverflow.com/a/20418640[Overriding and calling same method in Base class constructor in C#]
* Eric Lippert's blog - https://ericlippert.com/2008/02/15/why-do-initializers-run-in-the-opposite-order-as-constructors-part-one[Why Do Initializers Run In The Opposite Order As Constructors?]

include::../rspecator.adoc[]
include::../rspecator.adoc[]