I'd like to mimic the F# 'with' keyword (which can be used on records) in C#.
For now, when i create a new immutable class, I just add manually some custom "with" methods like this :
public class MyClass
{
public readonly string Name;
public readonly string Description;
public MyClass(string name, string description)
{
this.Name = name;
this.Description = description;
}
// Custom with methods
public MyClass WithName(string name)
{
return new MyClass(name, this.Description);
}
public MyClass WithDescription(string description)
{
return new MyClass(this.Name, description);
}
}
For my personal c# development, I tried to create a generic method to do this (in a perfect world, I would use F#). The "best" I did is something like :
public static class MyExtensions
{
public static TSource With<TSource, TField>(
this TSource obj,
string fieldName,
TField value)
where TSource : class
{
// Reflection stuff to use constructor with the new value
// (check parameters names and types)...
}
}
It works but I'm not quite satisfied because I lose compile time errors by using a string parameter (for now I don't care of performance issues).
I'd really like to be able to write something like the code below, where I replace the string parameter by a "projection" lambda :
var myClass1 = new MyClass("name", "desc");
var myClass2 = myClass1.With(obj => obj.Name, "newName");
My extension method would look something like :
public static TSource With<TSource, TField>(
this TSource obj,
Expression<Func<TSource, TField>> projection,
TField value)
where TSource : class
{
// TODO
}
So here are my questions :
The from method allows for “editing” operations on immutable values by initializing the builder with attribute values taken from an existing immutable object. This could be used to prevent structural sharing as happens with copy-methods, or to accumulate collection elements from attributes of multiple values.
Immutable class in java means that once an object is created, we cannot change its content. In Java, all the wrapper classes (like Integer, Boolean, Byte, Short) and String class is immutable. We can create our own immutable class as well.
This can certainly be done and is approach that is used in several places including Entity Framework. In EF it is used for including properties in a query.
DbContext.Categories.Include(c=>c.Products)
A query over this set will also pull the products in a category. You can examine the expression in your extension method and extract the member info like this
((System.Linq.Expressions.MemberExpression)projection.Body).Member
Of course in practice you will need some error handling to make sure the expression is a member expression. Then you can use reflection to set the appropriate property. You will need a setter for this to work but you can access private setters via reflection so the types can still be effectively immutable. This is not a perfect solution but I guess it is close enough.
I am not aware of any existing implementation of such a method. I am curious to see your full version.
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