2012-05-18 9 views
9

Nhóm C# trước đây đã xem xét thêm thuộc tính mở rộng, sự kiện, v.v. vào C#.Bảo quản trạng thái theo phương pháp mở rộng

mỗi Eric Lippert:

http://blogs.msdn.com/b/ericlippert/archive/2009/10/05/why-no-extension-properties.aspx

Đối với các tính năng này có ích tuy nhiên, họ sẽ phải có khả năng lưu trữ một số loại mới của nhà nước với một đối tượng. Có vẻ như cách duy nhất để làm điều này là sử dụng từ điển và kết hợp từng cá thể của một đối tượng với bất kỳ trạng thái bổ sung nào. Sẽ rất hữu ích nếu có thể sao chép chức năng này "thủ công" bằng cách tạo từ điển của riêng tôi (và có thể lấy/đặt các phương thức mở rộng). Tuy nhiên, để kết hợp một cá thể cụ thể của một đối tượng với một số trạng thái, bạn sẽ cần phải băm số tham chiếu thực tế thực tế cho đối tượng. Trong một ngôn ngữ khác, bạn có thể làm điều này bằng cách băm vị trí bộ nhớ của nó, tuy nhiên trong C# không được bảo đảm ở trạng thái không đổi và việc sử dụng mã không an toàn để thực hiện tính năng này là rất lý tưởng.

Có ai biết nếu có thể lấy một số tham chiếu có thể băm vào đối tượng không thay đổi khi thay đổi trạng thái nội bộ của đối tượng không? Rõ ràng là có một số cơ chế nội bộ để theo dõi các đối tượng riêng lẻ bất kể vị trí bộ nhớ của chúng, nhưng tôi không chắc liệu nó có được tiếp xúc với mã người dùng hay không.

Lưu ý: Đơn giản chỉ băm đối tượng chính nó sẽ không hoạt động chút nào, vì GetHashCode() phụ thuộc vào trạng thái bên trong của đối tượng không nằm trên đối tượng.

Cảm ơn mọi thông tin chi tiết.

+1

Ugh, tôi thích các phương pháp mở rộng vì chúng KHÔNG xử lý trạng thái của đối tượng và chỉ là đường cú pháp, tôi sợ làm bất cứ điều gì thực sự làm mờ đường quá nhiều ...Điều đó nói rằng, nó là một suy nghĩ thú vị, tất nhiên ... –

Trả lời

11

Bạn đang tìm kiếm ConditionalWeakTable class.

+3

Wow. Một trường hợp khác của 'Sau 10 năm của C#, tôi vẫn khám phá ra mọi thứ'. Cảm ơn. –

+1

@KooKiz: Hãy thử lớp 'PluralizationService' – SLaks

+0

Tôi cũng ngạc nhiên vì tôi chưa từng thấy điều này trước đây. Có vẻ như nó hoạt động bằng cách truyền tới đối tượng và sau đó gọi RuntimeHelpers.GetHashCode(), (một số phép thuật thời gian chạy). Bạn có biết ý nghĩa hiệu quả của việc sử dụng lớp này không? – MgSam

0

** WHOLE ANSWEr EDITED ** Các thuộc tính được lưu giữ trong từ điển sử dụng tham chiếu yếu đối với các đối tượng như khóa và dictionay với cặp đối tượng chuỗi để lưu trữ các thuộc tính và giá trị của chúng.

Để đặt, nhận hoặc xóa thuộc tính cho một đối tượng, đối tượng sẽ tìm kiếm trong các tham chiếu yếu trong từ điển.

Có thể có hai cách để xử lý tài sản không được sử dụng:

  • kiểm tra các IsAlive của tham chiếu yếu, và loại bỏ các mục trong từ điển nếu sai
  • thực hiện IDisposable trong "mở rộng "đối tượng và gọi một phương thức mở rộng loại bỏ các thuộc tính trên đối tượng đang được xử lý.

Tôi đã bao gồm khối tùy chọn sử dụng trong mã mẫu, để bạn có thể gỡ lỗi và xem cách Xử lý cuộc gọi phương thức mở rộng RemoveProperties. Đây là khóa học tùy chọn, và phương thức sẽ được gọi khi đối tượng là GC'ed.

Mẫu làm việc của ý tưởng, sử dụng WeakReference, từ điển tĩnh và IDisposable.

using System; 
using System.Collections.Generic; 
using System.Linq; 

namespace ConsoleApplication3 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      using (PropertyLessClass plc = new PropertyLessClass()) 
      { 
       plc.SetProperty("age", 25); 
       plc.SetProperty("name", "John"); 
       Console.WriteLine("Age: {0}", plc.GetProperty("age")); 
       Console.WriteLine("Name: {0}", plc.GetProperty("name")); 
      } 
      Console.ReadLine(); 
     } 
    } 
} 

public class PropertyLessClass : IDisposable 
{ 
    public void Dispose() 
    { 
     this.DeleteProperties(); 
    } 
} 

public static class PropertyStore 
{ 
    private static Dictionary<WeakReference, Dictionary<string, object>> store 
     = new Dictionary<WeakReference, Dictionary<string, object>>(); 

    public static void SetProperty(this object o, string property, object value) 
    { 
     var key = store.Keys.FirstOrDefault(wr => wr.IsAlive && wr.Target == o); 
     if (key == null) 
     { 
      key = new WeakReference(o); 
      store.Add(key, new Dictionary<string, object>()); 
     } 
     store[key][property] = value; 
    } 

    public static object GetProperty(this object o, string property) 
    { 
     var key = store.Keys.FirstOrDefault(wr => wr.IsAlive && wr.Target == o); 
     if (key == null) 
     { 
      return null; // or throw Exception 
     } 
     if (!store[key].ContainsKey(property)) 
      return null; // or throw Exception 
     return store[key][property]; 
    } 

    public static void DeleteProperties(this object o) 
    { 
     var key = store.Keys.FirstOrDefault(wr => wr.IsAlive && wr.Target == o); 
     if (key != null) 
     { 
      store.Remove(key); 
     } 
    } 
} 
+0

Tôi nghĩ bạn hiểu nhầm câu hỏi. – MgSam

+0

Tôi nghĩ là vậy. Tôi đã thêm một số văn bản vào câu trả lời của tôi. – JotaBe

+0

Cảm ơn bạn đã phản hồi. Tuy nhiên, một vấn đề với mã này là nó sử dụng các chuỗi ma thuật đánh máy yếu để đại diện cho các tên thuộc tính. Với các phương thức mở rộng trên chính lớp đó, bạn có thể làm cho các phương thức get/set không bị vấn đề đó. – MgSam