2011-01-18 53 views
7

Có thể có một cái gì đó như thế này trong C#? Tôi không phải là rất chắc chắn:Nhiều thuộc tính chỉ mục trên một loại?

class Library 
{ 
    public string Books[string title] 
    { 
     get{return this.GetBookByName(string title);} 
    } 

    public DateTime PublishingDates[string title] 
    { 
     get{return this.GetBookByName(string title).PublishingDate;} 
    } 
} 

Vì vậy, nó có thể được sử dụng như ví dụ:

myLibrary.Books["V For Vendetta"] 
myLibrary.PublishingDates["V For Vendetta"] = ... 

Vì vậy, phương pháp thành viên hoàn chỉnh của tôi rằng tôi cần phải thực hiện trong khuôn khổ của tôi (bằng cách gọi họ) là:

GetCustomStringValue (key) 
GetCustomIntValue (key) 
GetCustomBoolValue (key) 
GetCustomFloatValue (key) 
SetCustomStringValue (key) 
SetCustomIntValue (key) 
SetCustomBoolValue (key) 
SetCustomFloatValue (key) 

Tôi muốn thực hiện chúng rõ ràng hơn theo loại của riêng tôi.

+1

Điểm này là gì? Tại sao bạn không thể sử dụng các phương pháp thông thường cũ để nhận và thiết lập? – Timwi

+0

Chỉ cần nghĩ rằng ai đó có thể đưa ra giải pháp tốt hơn. Nó không có vẻ thanh lịch để có nó theo cách này, nhưng chỉ là thí nghiệm. –

Trả lời

11

Cách duy nhất bạn có thể thực hiện việc này là phải có Books là thuộc tính trả về loại có chỉ mục phù hợp riêng. Dưới đây là một cách tiếp cận có thể:

public class Indexer<TKey, TValue> 
{ 
    private Func<TKey, TValue> func; 

    public Indexer(Func<TKey, TValue> func) 
    { 
     if (func == null) 
      throw new ArgumentNullException("func"); 

     this.func = func; 
    } 

    public TValue this[TKey key] 
    { 
     get { return func(key); } 
    } 
} 

class Library 
{ 
    public Indexer<string, Book> Books { get; private set; } 
    public Indexer<string, DateTime> PublishingDates { get; private set; } 

    public Library() 
    { 
     Books = new Indexer<string, Book>(GetBookByName); 
     PublishingDates = new Indexer<string, DateTime>(GetPublishingDate); 
    } 

    private Book GetBookByName(string bookName) 
    { 
     // ... 
    } 

    private DateTime GetPublishingDate(string bookName) 
    { 
     return GetBookByName(bookName).PublishingDate; 
    } 
} 

Nhưng bạn nên nghiêm túc xem xét cung cấp một thực hiện IDictionary<,> thay vì sử dụng phương pháp này, vì nó sẽ cho phép các công cụ tiện lợi khác, như đếm cặp khóa-giá trị, vv

+1

Cảm ơn, đây là giải pháp rất tuyệt. –

+0

@Joan: Không sao cả. Đảm bảo bạn nhận được bản sao mới nhất vì tôi vừa sửa Sách/PublishingDates là các trường công khai - bây giờ chúng là các thuộc tính. – cdhowie

+0

Cảm ơn người đàn ông, tôi tự hỏi nếu điều này cũng sẽ cho phép tôi để thiết lập các giá trị chỉ số? Giống như myLib.Books ["name"] = new Book(); v.v. –

0

Tại sao không chỉ sử dụng các phương pháp?

class Library 
{  
    public string Books(string title) 
    {   
     return this.GetBookByName(title); 
    }  

    public DateTime PublishingDates(string title) 
    {   
     return this.GetBookByName(title).PublishingDate; 
    } 
} 
+0

Tôi có thể nhưng ví dụ cụ thể này tôi có cả hai phương thức Get và Set làm việc như thế này, vì vậy tôi nghĩ nó sẽ sạch hơn nếu tôi có một thuộc tính chỉ mục cho mỗi cái thực hiện cả hai, thay vì 2 phương thức. Chúng khác nhau về kiểu trả về và phần còn lại là như nhau, bạn truyền một khóa, nhận giá trị kiểu int, bool, float hoặc string. –

+2

Tôi đồng ý rằng nó không biên dịch, nhưng điểm của @ Kirk vẫn hợp lệ. –

+1

Bạn cần phải loại bỏ được! –

1

C# không hỗ trợ nó, thật không may. Nó chỉ nhận ra thuộc tính this[], mà thực sự chỉ là một thuộc tính có thể lập chỉ mục có tên là Item khi được biên dịch. CLI hỗ trợ bất kỳ số thuộc tính có thể lập chỉ mục nào và có thể được phản ánh bằng một số ngôn ngữ khác như F #, nơi bạn có thể xác định thuộc tính của riêng mình.

Ngay cả khi bạn tự xác định trong CIL hoặc ngược lại, bạn vẫn không thể gọi chúng từ C# như bạn muốn, bạn cần thực hiện cuộc gọi thủ công tới get_Books(index); cho thuộc tính có tên Books. Tất cả các thuộc tính chỉ là cú pháp cú pháp cho các cuộc gọi phương thức như vậy. C# chỉ nhận ra thuộc tính có tên là Item là có thể lập chỉ mục.

+0

đây là một trong những lý do của tôi vì sao VB.NET tốt hơn C# - nó hỗ trợ các thuộc tính parameterised (indexed). (Đừng lo, tôi cũng có nhiều lý do vì sao C# tốt hơn VB.NET!) – AAT

+0

@AAT, bạn có thể đăng một liên kết tới một số mẫu mã cho vb.net không? Tôi tò mò về nó. –

+0

@Janan - nó không khó: bạn chỉ cần định nghĩa một thuộc tính như "Property Property PropertyName (paramName như ParamType) là PropertyType". Bạn có thể sử dụng bất kỳ loại hoặc số tham số nào. – AAT

2

Trong C#, người lập chỉ mục phải được gọi là this (xem http://msdn.microsoft.com/en-us/library/aa664459(v=VS.71).aspx). Bạn có thể quá tải các chỉ mục, nhưng hãy nhớ rằng C# không cho phép quá tải dựa trên kiểu trả về chỉ. Vì vậy, trong khi bạn có thể có:

public int this[int i] 
public string this[string s] 

Bạn có thể không có:

hướng dẫn thiết kế
public int this[int i] 
public string this[int i] 

.NET thư viện lớp khuyên bạn nên có chỉ có một indexer mỗi lớp.

Vì vậy, trong trường hợp của bạn, không có cách nào để làm những gì bạn đang yêu cầu bằng cách sử dụng chỉ mục.

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