2014-11-17 11 views
7

Ich möchte das F # "mit" Schlüsselwort (das für Datensätze verwendet werden kann) in C# nachahmen.Erstellen Sie eine "mit" -Methode auf immutables

Vorerst, wenn ich eine neue unveränderliche Klasse erstellen, füge ich nur manuell einige benutzerdefinierte „mit“ Methoden wie folgt aus:

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); 
    } 
} 

Für meine persönliche C# Entwicklung habe ich versucht, ein gattungsgemäßes Verfahren zu schaffen, zu tun dies (in einer perfekten Welt würde ich F # verwenden). Die „beste“ habe ich so etwas wie:

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)... 
     } 
    } 

Es funktioniert, aber ich bin nicht ganz zufrieden, weil ich Zeit Fehler verlieren kompilieren durch einen String-Parameter verwenden (jetzt ist mir egal, von Performance-Probleme).

ich wirklich in der Lage sein möchten, so etwas wie den Code unten zu schreiben, wo ich den String-Parameter durch eine „Projektion“ Lambda ersetzen: Verfahren

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

Meine Erweiterung würde wie etwas aussehen:

public static TSource With<TSource, TField>(
     this TSource obj, 
     Expression<Func<TSource, TField>> projection, 
     TField value) 
     where TSource : class 
    { 
     // TODO 
    } 

So sind hier meine Fragen:

  • Ist es möglich, Reflexion über die Projektion des resu zu verwenden lt und den Feldnamen daraus bekommen?
  • Hat jemand anderes bereits eine robuste "mit" -Methode in C# erstellt?
+0

Ich habe Ihren Titel bearbeitet. Bitte lesen Sie: "[Sollten die Fragen" Tags "in ihren Titeln enthalten?] (Http://meta.stackexchange.com/questions/19190/)", wo der Konsens "nein, sollten sie nicht" ist. –

+0

Für Ihre erste Frage siehe http://stackoverflow.com/questions/671968/retrieving-property-name-from-lambda-expression. Ihre zweite ist nicht wirklich ein Thema für StackOverflow, fürchte ich. –

+1

Siehe auch http://stackoverflow.com/questions/2820660/get-name-of-property-as-a-string –

Antwort

2

Dies kann sicherlich getan werden und ist Ansatz, der an mehreren Orten einschließlich Entity Framework verwendet wird. In EF wird es zum Einschließen von Eigenschaften in eine Abfrage verwendet.

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

Eine Abfrage über diesen Satz wird auch die Produkte in einer Kategorie ziehen. Sie können den Ausdruck in Ihrer Erweiterungsmethode untersuchen und das Element info extrahieren wie dieses

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

Natürlich in der Praxis Sie einige Fehler müssen sicherstellen Ausdruck der Ausdruck ist Mitglied machen Handhabung. Dann können Sie mithilfe der Reflektion die entsprechende Eigenschaft festlegen. Sie benötigen einen Setter, damit dies funktioniert, aber Sie können über Reflektion auf private Setter zugreifen, sodass die Typen weiterhin effektiv unveränderbar sind. Dies ist keine perfekte Lösung, aber ich denke, es ist nahe genug.

Mir ist keine vorhandene Implementierung einer solchen Methode bekannt. Ich bin gespannt auf deine Vollversion.

+0

Danke, ich werde diesen Beitrag bearbeiten, wenn meine Implementierung beendet ist. –

0

Da F # und C# beide .NET-Sprachen sind und somit auf dieselbe IL kompiliert werden, könnten Sie auch überlegen, wie F # unter der Haube funktioniert. Es gibt ein paar Möglichkeiten this-

  • Kompilieren einig einfaches F # Code, und dann dekompilieren es in C# unter Verwendung eines IL zu sehen Werkzeug cdoe wie DotPeek.
  • Kompilieren einige F # -Code, und untersuchen sie mit einem IL-Inspektionswerkzeug wie ILDasm

obwohl die zweite Option einige Kenntnisse von IL erfordert, könnte es auch mehr als nützlich erweisen, einige der feinen Unterschiede zu sehen, dass C# möglicherweise überhaupt nicht kompilieren kann.

+0

"mit" ist ein Sprachschlüsselwort, das vom F # -Compiler bekannt ist. Ich bin mir ziemlich sicher, dass der einzige IL-Code, den ich sehen werde, "nur" ein Konstruktor-Aufruf ist. –

Verwandte Themen