Create a method with immutable

I would like to imitate the F # keyword with a key (which can be used in entries) in C #.

Now, when I create a new immutable class, I just manually add some custom c methods, for example:

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 for this (in an ideal world, I would use F #). The "best" I did was 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)... } } 

This works, but I'm not completely satisfied, because I am losing compile-time errors using a string parameter (so far I don't care about performance issues).

I would really like to write something like the code below, where I will replace the string parameter with the "projection" lambda:

 var myClass1 = new MyClass("name", "desc"); var myClass2 = myClass1.With(obj => obj.Name, "newName"); 

My extension method would look something like this:

  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:

  • Is it possible to use reflection of the projection result and get the field name from it?
  • Has anyone else already made a reliable c method in C #?
+7
immutability reflection c # lambda
source share
2 answers

This can certainly be done, and it is an approach that is used in several places, including the Entity Framework. In EF, it is used to include properties in a query.

 DbContext.Categories.Include(c=>c.Products) 

A request for this set will also pull products into categories. You can check the expression in your extension method and extract member information like this

 ((System.Linq.Expressions.MemberExpression)projection.Body).Member 

Of course, in practice, you will need some error handling to make sure that the expression is a member expression. Then you can use reflection to set the corresponding property. You will need an installer to do this, but you can access private setters through reflection so that types can still be effectively immutable. This is not an ideal solution, but I think it is close enough.

I am not aware of any existing implementation of such a method. I am curious to see your full version.

+2
source share

Since F # and C # are .NET languages ​​and, thus, compiled with the same IL, you can also think about how F # does its work under the hood. There are several ways to see this -

  • Compile simple F # code and then decompile it in C # using an IL to cdoe tool like DotPeek .
  • Compile some F # code and review it with an IL validation tool like ILDasm

although the second option requires some working knowledge of IL, it may also be more useful to see some of the subtle differences that C # cannot compile at all.

0
source share

All Articles