2011-01-18 13 views
7

Czy jest coś takiego w C#? Nie jestem bardzo pewny:Wiele właściwości indeksu na typie?

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

Więc to może być używane jako takie:

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

Więc moje pełne metody członkowskie, które muszę wdrożyć w moim ramy (przez nazywając je) są:

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

Chcę zaimplementować je czystsze w moim własnym typie.

+1

Jaki jest tego cel? Dlaczego nie możesz po prostu użyć zwykłych starych, normalnych metod do zdobywania i ustawiania? – Timwi

+0

Po prostu myśl, że ktoś może wymyślić lepsze rozwiązanie. Wydaje się, że nie jest tak elegancko, ale po prostu eksperymenty. –

Odpowiedz

11

Jedynym sposobem można to zrobić byłoby mieć Books być nieruchomość, która zwraca typ, który ma własną odpowiedniego indeksowania. Oto jeden z możliwych rozwiązań:

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

Ale należy poważnie rozważyć zapewnienie realizacji IDictionary<,> zamiast korzystania z tej metody, ponieważ pozwoli to inne przydatne rzeczy, jak wyliczenie par klucz-wartość, itp

+1

Dzięki, to jest bardzo fajne rozwiązanie. –

+0

@ Joan: Nie ma problemu. Upewnij się, że otrzymałeś najnowszą kopię, ponieważ właśnie naprawiłem Books/PublishingDates jako publiczne pola - teraz są to właściwości. – cdhowie

+0

Dzięki stary, zastanawiam się, czy to również pozwoliłoby ustawić wartości indeksu? Podobnie jak myLib.Books ["name"] = new Book(); itp? –

0

Dlaczego po prostu nie stosować metod?

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

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

Mogę, ale ten konkretny przykład mam zarówno metody Get i Set, które działają w ten sposób, więc pomyślałem, że byłoby czystsze, gdybym miał jedną właściwość indeksu dla każdego, który wykonuje obie, zamiast 2 metod. Różnią się typami zwrotów, a reszta jest taka sama, przekazujesz klucz, otrzymujesz wartość typu int, bool, float lub string. –

+2

Zgadzam się, że nie kompiluje się, ale punkt @ Kirka jest nadal ważny. –

+1

Musisz się pozbyć tych rzeczy! –

1

C# niestety nie obsługuje tego. Rozpoznawana jest tylko właściwość this[], która jest po prostu właściwością indeksowaną o nazwie Item podczas kompilacji. Interfejs CLI obsługuje jednak dowolną liczbę właściwości indeksowanych, co może znaleźć odzwierciedlenie w innych językach, takich jak F #, w których można zdefiniować własne.

Nawet jeśli zdefiniujesz własne w CIL lub w inny sposób, nadal nie możesz wywoływać ich z C#, jak chcesz, musisz wykonać ręczne wywołanie do get_Books(index); dla właściwości o nazwie Books. Wszystkie właściwości są po prostu syntaktycznym cukrem dla takich wywołań metod. C# rozpoznaje tylko właściwość o nazwie Item jako indeksowalną.

+0

jest to jeden z moich argumentów, dlaczego VB.NET jest lepszy niż C# - obsługuje właściwości sparametryzowane (indeksowane). (Nie martw się, mam tyle samo powodów, dla których C# jest lepsze niż VB.NET!) – AAT

+0

@AAT, czy możesz opublikować link do niektórych próbek kodu dla vb.net? Ciekawi mnie to. –

+0

@Joan - nie jest to trudne: wystarczy zdefiniować właściwość taką jak "Właściwość publiczna PropertyName (paramName jako ParamType) jako PropertyType". Możesz użyć dowolnego rodzaju lub liczby parametrów. – AAT

2

W języku C# indeksatory muszą być nazywane this (patrz http://msdn.microsoft.com/en-us/library/aa664459(v=VS.71).aspx). Możesz przeciążać indeksatory, ale pamiętaj, że C# nie pozwala na przeciążanie tylko na podstawie typu zwracanego. Tak więc, podczas gdy można mieć:

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

Mogłeś nie mieć:

wytyczne projektowe
public int this[int i] 
public string this[int i] 

biblioteki klas .NET polecam mające tylko jeden podziałowe na klasy.

W twoim przypadku nie można zrobić tego, o co pytasz, używając tylko indeksatorów.

Powiązane problemy