I'm using C# 12. In C# 12 I can use primary constructor:
Implementation 1 :
public class Calculation(int a,int b)
{
public int Addition() => a + b;
public int Subtraction() => a - b;
}
Implementation 2 :
public class Calculation(int a,int b)
{
private int _a { get; init; } = a;
private int _b { get; init; } = b;
public int Addition() => _a + _b;
public int Subtraction() => _a - _b;
}
When I'm calling this method like :
console.WriteLine(new Calculation(10,25).Addition());
Both implementation working fine, so I'd like to know whether there is any advantage to using the longer Implementation 2 over the shorter Implementation 1.
There is no point in creating fields/properties yourself this way, since the compiler will create them for you in this case (decompilation @sharplab.io).
From the Tutorial: Explore primary constructors doc (they use struct
but the handling of the primary ctor for classes is basically the same):
public struct Distance(double dx, double dy) { public readonly double Magnitude => Math.Sqrt(dx * dx + dy * dy); public readonly double Direction => Math.Atan2(dy, dx); public void Translate(double deltaX, double deltaY) { dx += deltaX; dy += deltaY; } public Distance() : this(0,0) { } }
In the previous example, the primary constructor properties are accessed in a method. Therefore the compiler creates hidden fields to represent each parameter. The following code shows approximately what the compiler generates. The actual field names are valid CIL identifiers, but not valid C# identifiers.
public struct Distance { private double __unspeakable_dx; private double __unspeakable_dy; public readonly double Magnitude => Math.Sqrt(__unspeakable_dx * __unspeakable_dx + __unspeakable_dy * __unspeakable_dy); public readonly double Direction => Math.Atan2(__unspeakable_dy, __unspeakable_dx); public void Translate(double deltaX, double deltaY) { __unspeakable_dx += deltaX; __unspeakable_dy += deltaY; } public Distance(double dx, double dy) { __unspeakable_dx = dx; __unspeakable_dy = dy; } public Distance() : this(0, 0) { } }
The potential downside is that the generated field is mutable:
public class Calculation(int a, int b)
{
public void Mutate() => a = 100;
// ...
}
Though your approach does not fix that but introduces some clutter when you can confuse _a
and a
. There is no way to mark the generated field as readonly
for now (but there are plans for the feature - see this LDM notes doc and this proposal) but you can shadow the ctor parameter by using field with the same name (or property):
public class Calculation2(int a, int b)
{
private readonly int a = a;
private readonly int b = b;
// public void Mutate() => a = 100; // does not compile
public int Addition() => a + b;
public int Subtraction() => a - b;
}
See also:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With