C
C#11mo ago
Loup&Snoop

✅ Immutable object with mutable clone

I have a class EntityData which is full of fields that need to be read only (everything public get, private set). I want to be able to make a different object that is a mutable clone, which behaves like EntityData in every way except every property is public. During runtime, I will have multiple instances of a class (EntityDataHolder) which will get fed an immutable original EntityData, and then make a mutable clone so that this particular instance of EntityDataHolder can modify it freely. I will later add more fields to EntityData, and I don’t want its definition and its clone’s definition to get messed up/misaligned (ie I want to avoid writing every field 4 times to make one on the original, clone, and clone-copying class all match up). What is a clean way to do this?
8 Replies
Loup&Snoop
Loup&Snoop11mo ago
I assume I need System.Reflection, but I’m not sure.
Angius
Angius11mo ago
Either that, or source generators.
Loup&Snoop
Loup&Snoop11mo ago
well, how would I do this? I have code to make a hard copy of an instance of a class, but idk how to define a class to have all the same fields as another class AND then clone them and potentially without calling methods using reflections constantly, because this will get expensive quick
Angius
Angius11mo ago
Source generators are your best bet, then You'd have a
public class Source
{
public int Foo { get; init; }
public string Bar { get; init; }
}
public class Source
{
public int Foo { get; init; }
public string Bar { get; init; }
}
and
[MutableFrom<Source>()]
public partial class Target {}
[MutableFrom<Source>()]
public partial class Target {}
Then, a generator that looks for classes with the attribute, takes the source type from it, then iterates over its properties and writes a new class
// not actual code
using var sb = new StringBuilder();
sb.Append($"public partial class {class.Name} \n\{");
foreach (var prop in props)
{
sb.Append($"\tpublic {prop.Type.Name} {prop.Name} \{ get; set; \} ");
}
sb.Append("}");
// not actual code
using var sb = new StringBuilder();
sb.Append($"public partial class {class.Name} \n\{");
foreach (var prop in props)
{
sb.Append($"\tpublic {prop.Type.Name} {prop.Name} \{ get; set; \} ");
}
sb.Append("}");
Which will generate
public partial class Target
{
public int Foo { get; set; }
public string Bar { get; set; }
}
public partial class Target
{
public int Foo { get; set; }
public string Bar { get; set; }
}
You could have it generate a FromSource method inside of that class as well So you can just do
var mutableClone = Target.FromSource(immutableSource);
var mutableClone = Target.FromSource(immutableSource);
Loup&Snoop
Loup&Snoop11mo ago
oh shit, that sounds like what I need Where do I get this MutableFrom attribute? I don’t see it anywhere via google
Angius
Angius11mo ago
Ah, right, you make it Just like the generator
Loup&Snoop
Loup&Snoop11mo ago
could you link me to an implementation/tutorial? That’s a vital step lol or maybe the name of it oic it is called a source generator. I can take it from here. ty
Accord
Accord11mo ago
Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.