2013-08-09 17 views
12

Ví dụ trong F # chúng ta có thể xác địnhChúng tôi có thể truy cập vào tính năng sao chép và cập nhật F # từ C#?

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

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

và cập nhật nó tôi có thể làm

let myRecord2 = { myRecord1 with Y = 100; Z = 2 } 

Đó là rực rỡ và thực tế là hồ sơ tự động thực hiện IStructuralEquality không có nỗ lực nhiều khiến tôi muốn cho điều này trong C#. Tuy nhiên Có lẽ tôi có thể xác định hồ sơ của tôi trong F # nhưng vẫn có thể thực hiện một số cập nhật trong C#. Tôi tưởng tượng một API như

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

Có cách nào không và tôi không để ý đến các hack bẩn, để triển khai CopyAndUpdate như trên? C# signiture cho CopyAndUpdate sẽ

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

Có thể điều này sẽ hữu ích: http://v2matveev.blogspot.com/2010/05/copy-and-update-in-c.html – desco

+0

bản sao có thể có của [C#: cách xác định phương thức tiện ích mở rộng là "bằng "trong F #?] (http://stackoverflow.com/questions/6832880/c-how-to-define-an-extension-method-as-with-in-f) –

Trả lời

7

Nó có thể được thực hiện, nhưng làm điều đó đúng sẽ là khá khó khăn (và nó chắc chắn sẽ không phù hợp trong câu trả lời của tôi). Việc thực hiện đơn giản sau đây giả định rằng đối tượng của bạn đã chỉ tài sản và tham số-less constructor đọc-viết:

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

này hơi đánh bại điểm, bởi vì có thể bạn sẽ muốn sử dụng này trên các loại không thay đổi - nhưng sau đó bạn luôn luôn có để gọi hàm tạo với tất cả các đối số và không rõ ràng cách liên kết các tham số hàm tạo (khi bạn tạo một cá thể) với các thuộc tính mà bạn có thể đọc.

Phương pháp With tạo ra một trường hợp mới, bản sao tất cả các giá trị tài sản và sau đó thiết lập một mà bạn muốn thay đổi (bằng cách sử dụng PropertyInfo chiết xuất từ ​​cây biểu hiện - mà không cần bất kỳ kiểm tra)

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

Sau đây bản demo cư xử như mong đợi, nhưng như tôi đã nói, nó có rất nhiều hạn chế:

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

nói chung, tôi nghĩ rằng sử dụng một phương pháp phản ánh dựa trên phổ quát như With đây có thể không phải su một ý tưởng hay, trừ khi bạn có nhiều thời gian để thực hiện nó đúng cách. Có thể dễ dàng hơn khi thực hiện một phương thức With cho mọi loại mà bạn sử dụng có tham số tùy chọn và đặt giá trị của chúng thành giá trị nhân bản (được tạo bằng tay) nếu giá trị không phải là null. Chữ ký sẽ là một cái gì đó như:

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

Tôi hy vọng sẽ xác định kỷ lục trong F # vì vậy tôi nhận được IStructuralEquality và IComparable miễn phí. Nó lỗi tôi tôi phải thực hiện bằng tay trong C#. – bradgonesurfing

+0

Tôi sẽ thử mã của bạn với một số bản ghi F # và xem nó có hoạt động không. – bradgonesurfing

+0

công việc tuyệt vời Tomas nhưng trong C# nó rơi xa ngắn để cho myRecord2 = {myRecord1 với Y = 100; Z = 2} – phillip

6

Bạn có thể đạt được một cái gì đó tương tự như sử dụng đối số tùy chọn:

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

Đây thực sự là khá gần với mã F # tạo ra để làm hồ sơ.

+0

Xin lỗi nhưng mục đích là sử dụng bản ghi F # khi chúng triển khai IStructualEquality và IComparable tự động. Tôi muốn sử dụng bản ghi F # từ C#. Big hỏi có lẽ nhưng tôi mệt mỏi của điền vào tất cả các boilerplate. – bradgonesurfing

+0

Xin lỗi. Tôi nghĩ bạn đang cố gắng sao chép các bản ghi trong C#. Tôi sẽ để lại câu trả lời của tôi trong trường hợp ai đó quan tâm. – Daniel

+1

Tôi nghĩ đây là câu trả lời hợp lý (+1 của tôi). Phương thức 'With' lấy tham số tùy chọn có thể được thêm vào như một phương thức mở rộng cho bản ghi F # (viết nhiều hơn, nhưng nó sẽ hoạt động nhanh hơn và tốt hơn :-)) –

Các vấn đề liên quan