Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using C# 9 records "with" expression can I copy and add to new derived instance?

Tags:

c#-9.0

Suppose I have the following:

public record Settings 
{
  public int Setting1 { get; init; }
}

public record MoreSettings : Settings
{
  public string Setting2 { get; init; }
}
...

var settings = new Settings { Setting1 = 1 };

// This is an error - CS0117
MoreSettings moreSettings = settings with { Setting2 = "A string setting" };

Is there a clean way to achieve this? Do I have the syntax wrong?
Obviously, in this contrived case I could just manually copy each base property.

var moreSettings = new MoreSettings { Setting1 = settings.Setting1, Setting2 = "A String!" };

But what if the base record type has lots of properties?

like image 838
John Maillet Avatar asked Oct 27 '20 15:10

John Maillet


People also ask

What is using () in C#?

The using statement causes the object itself to go out of scope as soon as Dispose is called. Within the using block, the object is read-only and can't be modified or reassigned. A variable declared with a using declaration is read-only.

How do I start learning C?

Get started with C. Official C documentation - Might be hard to follow and understand for beginners. Visit official C Programming documentation. Write a lot of C programming code - The only way you can learn programming is by writing a lot of code.


1 Answers

From your original question,

MoreSettings moreSettings = settings with { Setting2 = "A string setting" };

with keyword internally ensures call to the copy constructor of the type, before changing the specified properties. The Settings record, in the example, does not have a property called Settings2, which is why this is not allowed.

Regarding your second approach, if the base class has a lot properties, you could introduce an additional constructor for the MoreSettings record, which accepts an instance of Settings as workaround for not having to add each of the properties as in the second example given in OP.

Instead, you could,

public record MoreSettings : Settings
{
   public MoreSettings(Settings parent) : base(parent) { }
   public string Setting2 { get; init; }
}

Now you could call make the call as

MoreSettings moreSettings = new MoreSettings(settings) { Setting2 = "A string setting" };

You could also remove the MoreSettings on right hand side by making use of Target-Type New expressions in C# 9

MoreSettings moreSettings = new (settings)  { Setting2 = "A string setting" };
like image 73
Anu Viswan Avatar answered Dec 07 '22 17:12

Anu Viswan