2009-03-15 35 views
8

Có cách nào để truy cập trường sao lưu cho thuộc tính để thực hiện xác thực, thay đổi theo dõi, v.v. không?Tiếp nhận trường sao lưu trong thuộc tính tự động

Có thể làm như sau? Nếu không có bất kỳ kế hoạch nào để có nó trong .NET 4/C# 4?

public string Name 
{ 
    get; 
    set 
    { 
     if (value != <Keyword>) 
     { 
      RaiseEvent(); 
     } 
     <Keyword> = value; 
    } 
} 

Vấn đề chính tôi có là sử dụng thuộc tính tự động không cho phép tính linh hoạt tương tự trong xác thực, vv mà thuộc tính có trường hậu thuẫn rõ ràng. Tuy nhiên một trường sao lưu rõ ràng có bất lợi trong một số trường hợp cho phép lớp được chứa trong để truy cập trường sao lưu khi nó truy cập và sử dụng lại xác thực, thay đổi theo dõi vv của thuộc tính giống như bất kỳ lớp nào khác có thể truy cập tài sản bên ngoài.

Trong ví dụ trên truy cập vào các lĩnh vực sao lưu sẽ được scoped đến tài sản do đó ngăn ngừa gian lận của các xác nhận bất động sản, thay đổi theo dõi, vv

Edit: Tôi đã thay đổi < Sao Field> để < từ khóa >. Tôi sẽ đề xuất một từ khóa mới tương tự như giá trị. trường sẽ hoạt động tốt mặc dù tôi chắc chắn rằng nó đang được sử dụng trong nhiều mã hiện có.

Trả lời

3

Sau khi đọc nhận xét của bạn trong câu trả lời của Mehrdad, tôi nghĩ rằng tôi hiểu vấn đề của bạn tốt hơn một chút. Có vẻ như bạn đang quan tâm đến khả năng của nhà phát triển truy cập trạng thái riêng tư trong lớp họ đang viết, bỏ qua logic xác nhận của bạn, v.v. Điều này cho thấy rằng nhà nước không nên chứa trong lớp đó chút nào.

Tôi sẽ đề xuất chiến lược sau đây. Viết một lớp generic đại diện cho một ValidatedValue. Lớp này chỉ giữ giá trị sao lưu và chỉ cho phép truy cập/đột biến thông qua các phương thức get và set. Một đại biểu chỉ được truyền cho ValidatedValue để đại diện cho logic xác nhận:

public class ValidatedValue<T> 
{ 
    private T m_val; 
    public ValidationFn m_validationFn; 

    public delegate bool ValidationFn(T fn); 

    public ValidatedValue(ValidationFn validationFn) 
    { 
     m_validationFn = validationFn; 
    } 

    public T get() 
    { 
     return m_val; 
    } 

    public void set(T v) 
    { 
     if (m_validationFn(v)) 
     { 
      m_val = v; 
     } 
    } 
} 

Bạn có thể, tất nhiên, thêm nhiều đại biểu theo yêu cầu (ví dụ, để hỗ trợ trước/sau thông báo thay đổi).

Lớp học của bạn giờ đây sẽ sử dụng ValidatedValue thay cho cửa hàng sao lưu cho thuộc tính của bạn.

Ví dụ dưới đây cho thấy một lớp, MyClass, với một số nguyên được xác nhận là nhỏ hơn 100. Lưu ý rằng logic để ném một ngoại lệ là trong MyClass, không phải là ValidatedValue. Điều này cho phép bạn thực hiện các quy tắc xác nhận phức tạp phụ thuộc vào trạng thái khác có trong MyClass. Ký pháp lambda được sử dụng để xây dựng đại biểu xác thực - bạn có thể đã liên kết với một hàm thành viên thay thế.

public partial class MyClass 
{ 
    private ValidatedValue<int> m_foo; 

    public MyClass() 
    { 
     m_foo = new ValidatedValue<int>(
      v => 
      { 
       if (v >= 100) RaiseError(); 
       return true; 
      } 
     ); 
    } 

    private void RaiseError() 
    { 
     // Put your logic here.... 
     throw new NotImplementedException(); 
    } 

    public int Foo 
    { 
     get { return m_foo.get(); } 
     set { m_foo.set(value); } 
    } 
} 

Hy vọng rằng sẽ giúp - phần nào tắt chủ đề ban đầu, nhưng tôi nghĩ nội dung đó phù hợp hơn với mối quan tâm thực tế của bạn. Những gì chúng tôi đã làm được lấy logic xác nhận ra khỏi tài sản và đặt nó vào dữ liệu, đó là chính xác nơi bạn muốn nó.

+0

Đó là một giải pháp tốt nhưng rất nhiều mã khi truy cập trường theo cách tương tự chúng tôi truy cập giá trị mới trong trình thiết lập với từ khóa giá trị được gọn gàng hơn và thanh lịch hơn. –

+2

Bạn có thể làm cho cú pháp đẹp hơn bằng cách thêm toán tử = và co đến T trên lớp ValidatedValue. Về cơ bản bạn muốn nó hoạt động như một ValidatedValue là một T. –

1

Nếu bạn định làm như vậy, tại sao bạn đang sử dụng thuộc tính tự động ?!

Một thuộc tính đơn giản đã hoàn thành trong phiên bản 1.0. Tôi không nghĩ việc thêm độ phức tạp vào ngôn ngữ cho mọi trường hợp đặc biệt là hợp lý. Bạn có cần tài sản để làm đồng bằng cửa hàng/lấy mô hình hoặc cần nhiều hơn thế. Trong trường hợp sau, một tài sản bình thường sẽ làm.

+0

Lợi ích của tính tự động là bạn buộc phải sử dụng tài sản chứ không phải là lĩnh vực ủng hộ từ các phương thức trong lớp. –

+0

Tôi không thấy bất kỳ lợi ích nào trong việc buộc một lớp học không sử dụng những gì nó tuyên bố. Đây là lý do tại sao chúng tôi không có các công cụ sửa đổi truy cập 'riêng tư 'nhỏ hơn. –

+0

Tôi biết nhưng trong một số trường hợp, trường chỉ là lưu trữ. Không có lý do nào khác để tuyên bố nó và bạn muốn có thể kiểm soát cách truy cập bộ nhớ đó dù nó ở đâu. –

13

Không có. Nếu bạn muốn truy cập trường sao lưu, thì không sử dụng thuộc tính tự động và cuộn thuộc tính của riêng bạn.

Tôi đồng ý rằng sẽ thật tuyệt vời khi có trường chỉ có thể truy cập được bởi tài sản chứ không phải bởi phần còn lại của lớp học. Tôi sẽ sử dụng nó mọi lúc.

+0

Tôi muốn thực thi việc sử dụng thuộc tính từ bên trong lớp mà thuộc tính đang ở. Tôi không muốn mã trong lớp truy cập trực tiếp vào trường. –

+3

Các lớp học phải có khả năng tin tưởng bản thân để xử lý đúng các cá nhân của riêng mình. –

+2

IMO đây là câu trả lời cho câu hỏi * thực tế *. Câu trả lời được đánh dấu là câu trả lời là câu trả lời cho một câu hỏi tiếp tuyến riêng biệt:/ – Catskul

1

Bạn không thể làm điều này tôi sợ. Đó là một trong những lý do tôi bắt đầu viết MoXAML Power Toys, để cung cấp khả năng chuyển đổi các thuộc tính tự động thành các thuộc tính Thông báo.

+0

Có vẻ thú vị.Vẫn không giải quyết được vấn đề có một trường nằm xung quanh mà không nên truy cập ngoại trừ trong phạm vi của tài sản. –

6

Khi MSDN trạng thái:

"Trong C# 3.0 và sau đó, tự động thực hiện tính làm cho tài sản kê khai ngắn gọn hơn khi không có thêm lý được yêu cầu trong accessors tài sản Họ cũng cho phép. mã khách hàng để tạo các đối tượng Khi bạn khai báo thuộc tính là được hiển thị trong ví dụ sau, trình biên dịch tạo một trường riêng tư, ẩn danh chỉ có thể truy cập thông qua việc nhận và đặt thuộc tínhngười truy cập. "

Vì bạn có logic bổ sung trong những người truy cập, việc sử dụng các thuộc tính được tự động triển khai không phù hợp trong kịch bản của bạn.

Trong khi trường sao lưu tồn tại, nó được đặt tên bị ngắt để ngăn bạn tham chiếu dễ dàng - ý tưởng là bạn không bao giờ tham chiếu trực tiếp trường.Vì lợi ích, bạn có thể sử dụng Reflector để tháo rời mã của bạn và khám phá tên trường, nhưng tôi khuyên bạn không nên sử dụng trường trực tiếp vì tên này thực sự dễ bay hơi, vì vậy mã của bạn có thể bị hỏng bất kỳ lúc nào.

+0

Tôi đã ấn tượng rằng họ chỉ lý do cho tên bị xáo trộn là để đảm bảo nó là duy nhất. Bạn không chắc chắn nó làm thế nào. Nó thêm vào các ký tự lạ không hợp lệ cho một tên biến. –

+0

Những gì tôi không hiểu là lý do tại sao trường vô danh thậm chí cần một tên ... –

2

Không, nhưng bạn có thể trong một lớp con:

public class Base 
{ 
    public string Name 
    { 
     get; 
     virtual set; 
    } 
} 

public class Subclass : Base 
{ 
    // FIXME Unsure as to the exact syntax. 
    public string Name 
    { 
     override set 
     { 
      if (value != base.Name) 
      { 
       RaiseEvent(); 
      } 

      base.Name = value; 
     } 
    } 
} 
Các vấn đề liên quan