2013-08-09 17 views
12

F # Mesela biz YapabileceğimF # kopya ve güncelleme özelliğine C# dan erişebilir miyiz?

type MyRecord = { 
    X: int; 
    Y: int; 
    Z: int 
    } 

let myRecord1 = { X = 1; Y = 2; Z = 3; } 

tanımlayabilir ve güncelleştirmek için

parlak ve kayıtlar otomatik fazladan hiçbir çaba IStructuralEquality uygulamak gerçeği beni bunun için dilek yapar
let myRecord2 = { myRecord1 with Y = 100; Z = 2 } 

C#. Ancak belki de kayıtlarımı F # olarak tanımlayabilirim ancak yine de C# 'da bazı güncellemeleri yapabilirim. Ben

MyRecord myRecord2 = myRecord 
    .CopyAndUpdate(p=>p.Y, 10) 
    .CopyAndUpdate(p=>p.Z, 2) 

gibi bir API bir yolu var mı hayal ve ben yukarıdaki gibi CopyAndUpdate uygulamak, kirli kesmek sakıncası? CopyAndUpdate C# signiture

T CopyAndUpdate<T,P> 
    (this T 
    , Expression<Func<T,P>> selector 
    , P value 
    ) 
+1

Belki bu yararlı olacaktır: http://v2matveev.blogspot.com/2010/05/copy-and-update-in-c.html – desco

+0

[C#: olası bir uzantı yöntemini nasıl tanımlanır? "F #?" (http://stackoverflow.com/questions/6832880/c-how-to-define-an-extension-method-as-with-in-f) –

cevap

7

Yapılabilir, ancak düzgün yapıyor (ve kesinlikle cevabım sığmaz) oldukça zor olacak olacaktır. Aşağıdaki basit uygulama sizin nesne olduğu mal ve parametresi olmayan yapıcı salt yazma ettiğini varsayar:

class Person 
{ 
    public string Name { get; set; } 
    public int Age { get; set; } 
} 

muhtemelen değişmez türlerinde bu kullanmak istiyorum çünkü bu hafifçe noktası yendi - ama sonra her zaman var kurucuyu tüm argümanlarla çağırmak ve okuyabileceğiniz özelliklere sahip kurucu parametrelerini (bir örnek oluşturduğunuzda) nasıl bağlayacağınız açık değildir.

With yöntem yeni bir örnek, kopyalar tüm özellik değerlerini oluşturur ve daha sonra (kullanarak PropertyInfo ifade ağaç çıkarılan! - hiçbir denetimi olmadan) değiştirmek istediğiniz bir ayarlayan

public static T With<T, P>(this T self, Expression<Func<T, P>> selector, P newValue) 
{ 
    var me = (MemberExpression)selector.Body; 
    var changedProp = (System.Reflection.PropertyInfo)me.Member; 

    var clone = Activator.CreateInstance<T>(); 
    foreach (var prop in typeof(T).GetProperties()) 
    prop.SetValue(clone, prop.GetValue(self)); 

    changedProp.SetValue(clone, newValue); 
    return clone; 
} 

aşağıdaki beklendiği gibi demo davranır, ancak dediğim gibi, bu sınırlamalar çok var: Ben su olmayabilir burada With gibi evrensel bir yansıma tabanlı yöntem kullanılarak düşünmek genel olarak

var person = new Person() { Name = "Tomas", Age = 1 }; 
var newPerson = person.With(p => p.Age, 20); 

Doğru bir şekilde uygulamak için fazla zamanınız yoksa, iyi bir fikir. Kullandığınız her tür için isteğe bağlı parametreleri alan ve değerleri null değilse, değerlerini klonlanmış bir değere (el ile oluşturulan) ayarladığınız her tür için bir With yöntemini uygulamak daha kolay olabilir. Sen isteğe bağlı argümanları kullanarak benzer bir şey elde edebiliriz

public Person With(string name=null, int? age=null) { ... } 
+0

Kayıttaki yeri tanımlamayı umuyorum F # Yani IStructuralEquality ve IComparable ücretsiz olsun. Bu beni C# 'de elle uygulamak zorunda kalıyor. – bradgonesurfing

+0

Kodunuzu bazı F # kayıtlarıyla deneyeceğim ve çalışıp çalışmadığını kontrol edeceğim. – bradgonesurfing

+0

harika bir iş Tomas ama C# 'da çok az düşüyor myRecord2 = {myRecord1 ile Y = 100; Z = 2} – phillip

6

:

class MyRecord { 
    public readonly int X; 
    public readonly int Y; 
    public readonly int Z; 
    public MyRecord(int x, int y, int z) { 
     X = x; Y = y; Z = z; 
    } 
    public MyRecord(MyRecord prototype, int? x = null, int? y = null, int? z = null) 
     : this(x ?? prototype.X, y ?? prototype.Y, z ?? prototype.Z) { } 
} 

var rec1 = new MyRecord(1, 2, 3); 
var rec2 = new MyRecord(rec1, y: 100, z: 2); 

Bu aslında F # kayıtları için oluşturduğu koduna oldukça yakın imza gibi bir şey olurdu.

+0

Üzgünüz, ancak amaç, IStructualEquality ve IComparable'ı otomatik olarak uyguladıkça F # kayıtlarını kullanmaktır. F # kayıtlarını C# 'dan kullanmak istiyorum. Büyük sor belki ama ben tüm bu kalıbı doldurmaktan yoruldum. – bradgonesurfing

+0

Üzgünüz. C# 'da kayıtları çoğaltmaya çalıştığını sanıyordum. Kimsenin ilgilenmesi durumunda cevabımı bırakacağım. – Daniel

+1

Bunun mantıklı bir cevap olduğunu düşünüyorum (+1'm). İsteğe bağlı argümanlar alarak bir 'With' yöntemi F # kaydına bir uzantı yöntemi olarak eklenebilir (daha fazla yazma, ancak daha hızlı ve daha iyi çalışacaktır :-)) –