2009-04-27 25 views
13

Ok. Vì vậy, tôi có một số mã bản đồ điều khiển nhất định trên một winForm để tài sản nhất định trong một đối tượng, để làm những điều nhất định để kiểm soát khi những điều nhất định xảy ra với dữ liệu. Tất cả tốt và tốt, hoạt động tốt. Không phải vấn đề. Vấn đề là, để thêm các mục để lập bản đồ, tôi gọi một chức năng giống như:Trích xuất tên thuộc tính để phản ánh, với Intellisense và biên dịch thời gian kiểm tra

this.AddMapping(this.myControl,myObject,"myObjectPropertyName"); 

Vấn đề tôi gặp phải là nó là rất khó để nói, tại thời gian biên dịch, sự khác biệt giữa các dòng ở trên và dưới đây:

this.AddMapping(this.myControl,myObject,"myObjectPropretyName"); 

Kể từ khi tham số cuối cùng là một chuỗi, không có thời gian biên dịch kiểm tra hoặc bất cứ điều gì như thế đó sẽ thực thi rằng chuỗi bản thân thực sự tương ứng với một tên thuộc tính hợp lệ trên đối tượng nhất định. Ngoài ra, những thứ như Refactor và "Find All References" bỏ lỡ loại tham chiếu này, dẫn đến sự vui nhộn khi tên của bản thân tài sản thay đổi. Vì vậy, những gì tôi đang tự hỏi là có một số cách để thay đổi chức năng như vậy mà những gì tôi đang đi trong vẫn là một chuỗi đại diện cho tên tài sản trong một số cách, nhưng với thời gian biên dịch kiểm tra giá trị thực tế đi vào. có thể làm điều này với cây Expression, nhưng tôi đã đọc trên chúng và dường như không thấy kết nối. Tôi rất muốn làm điều gì đó như:

this.AddMapping(this.myControl,myObject,myObject.myObjectPropertyName); 

hoặc thậm chí

this.AddMapping(this.myControl,myObject.myObjectPropertyName); 

sẽ trở nên ngọt ngào!

Bất kỳ ý tưởng nào?

+0

Mất 6 hoặc 7 lần truy cập trước khi tôi có thể phát hiện sự khác biệt trong hai dòng mã của bạn. – jjnguy

+0

Chào mừng bạn đến địa ngục của tôi ... bây giờ tưởng tượng nó rải rác với từ viết tắt như CPCR, CPR, CLI, vv ... – GWLlosa

+0

Trong thời gian dài nhất tôi đã mong muốn một số loại VS thêm vào đó sẽ phân tích tất cả các chuỗi trong mã và kiểm tra chính tả chúng. Nó cũng sẽ đưa vào tài khoản vỏ lạc đà, và chính tả kiểm tra từng từ riêng lẻ. Ai đó cần phải viết rằng sucker .... – BFree

Trả lời

14

trong 3.5, Biểu thức là một cách để chỉ định tên thành viên làm mã; bạn có thể có:

public void AddMapping<TObj,TValue>(Control myControl, TObj myObject, 
     Expression<Func<TObj, TValue>> mapping) {...} 

rồi phân tích cú pháp cây biểu thức để nhận giá trị. Một chút không hiệu quả, nhưng không quá tệ.

Dưới đây là mã ví dụ:

public void AddMapping<TSource, TValue>(
     Control control, 
     TSource source, 
     Expression<Func<TSource, TValue>> mapping) 
    { 
     if (mapping.Body.NodeType != ExpressionType.MemberAccess) 
     { 
      throw new InvalidOperationException(); 
     } 
     MemberExpression me = (MemberExpression)mapping.Body; 
     if (me.Expression != mapping.Parameters[0]) 
     { 
      throw new InvalidOperationException(); 
     } 
     string name = me.Member.Name; 
     // TODO: do something with "control", "source" and "name", 
     // maybe also using "me.Member" 
    } 

gọi với:

AddMapping(myControl, foo, f => f.Bar); 
1

Bạn thực sự không nên chuyển các chuỗi ký tự vào dưới dạng tên thuộc tính. Thay vào đó, bạn nên sử dụng YourClass.PROPERTY_NAME_FOO.

Bạn nên khai báo các Chuỗi này dưới dạng các const trong lớp của bạn.

public const String PROPERTY_NAME_FOO = "any string, it really doesn't matter"; 
public const String PROPERTY_NAME_BAR = "some other name, it really doesn't matter"; 

Hoặc, bạn không phải lo lắng về Strings ở tất cả, tên thuộc tính chỉ:

public const int PROPERTY_NAME_FOO = 0; 
public const int PROPERTY_NAME_BAR = 1; //values don't matter, as long as they are unique 

Điều đó sẽ ngăn chặn chuỗi mà không đề cập đến một tài sản có giá trị từ đi vào gọi hàm .

Intelisense sẽ có thể hiển thị cho bạn tên thuộc tính từ bên trong lớp học của bạn dưới dạng đề xuất để tự động hoàn tất.

+0

Tôi đã nghĩ về điều đó, điều duy nhất làm phiền tôi là nó dư thừa ... Bây giờ bạn đang duy trì thông tin tài sản ở 2 nơi riêng biệt (chuỗi const và tên thuộc tính) có vẻ ít hơn tối ưu. – GWLlosa

+0

Bạn thực sự không phải sử dụng một String. Bạn chỉ có thể ánh xạ chúng vào ints hoặc bất cứ điều gì. Đó là tên quan trọng và thực tế là các giá trị là duy nhất. – jjnguy

+0

Nhưng nếu tôi không ánh xạ chúng thành chuỗi, làm thế nào để cuối cùng tôi có được một giá trị chuỗi? – GWLlosa

2

Xem xét sử dụng lambdas hoặc thậm chí System.Linq.Expressions cho điều này, với một trong số:

extern void AddMapping<T,U>(Control control, T target, Func<T,U> mapping); 
extern void AddMapping<T,U>(Control control, T target, Expression<Func<T,U>> mapping); 

Sau đó, gọi nó với

this.AddMapping(this.myControl, myObject, (x => x.PropertyName)); 

Sử dụng đối số Biểu thức nếu bạn cần tách rời cây cú pháp trừu tượng trong thời gian chạy, để thực hiện các việc phản chiếu như lấy tên thuộc tính dưới dạng chuỗi; cách khác, hãy để cho đại biểu thực hiện công việc câu cá ra dữ liệu bạn cần.

3

Để làm cho mọi việc dễ dàng hơn với các biểu thức dựa lamda khắc phục, tôi đã viết nó như một phương pháp khuyến nông.

public static string GetPropertyName<T>(this object o, Expression<Func<T>> property) 
    { 
     var propertyInfo = (property.Body as MemberExpression).Member as PropertyInfo; 
     if (propertyInfo == null) 
      throw new ArgumentException("The lambda expression 'property' should point to a valid Property"); 
     var propertyName = propertyInfo.Name; 
     return propertyName; 
    } 

Gọi như thế này

class testclass 
    { 
     public string s { get; set; } 
     public string s2 { get; set; } 
     public int i { get; set; } 

    } 

    [TestMethod] 
    public void TestMethod2() 
    { 
     testclass x = new testclass(); 
     string nameOfPropertyS = this.GetPropertyName(() => x.s); 
     Assert.AreEqual("s", nameOfPropertyS); 

     string nameOfPropertyI = x.GetPropertyName(() => x.i); 
     Assert.AreEqual("i", nameOfPropertyI); 

    } 

Okay, sử dụng như một phương pháp mở rộng thực sự là để thuận tiện như bạn có thể trên thực tế gọi phương thức trên một lớp đối với tài sản của bao phấn lớp. Tôi chắc chắn rằng nó có thể được cải thiện.

+0

Tôi có thể thấy một số ý kiến ​​liên quan đến việc sử dụng các phương pháp mở rộng, lý do tôi muốn để có được bàn tay của tôi về điều này là cho WPF Binding (mvvm) để bạn có thể gọi OnPropertyChanged (this.GetProperty (() => MyProperty); giúp giảm bớt một số vấn đề xung quanh sự an toàn thời gian biên dịch của việc ràng buộc wpf như vậy. Ít nhất nếu bạn thay đổi tên thuộc tính bạn nhận được một số thời gian an toàn biên dịch. Bạn vẫn phải chỉnh sửa văn bản ràng buộc trong xaml của bạn mặc dù ... –

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