2013-01-22 19 views
5

Chcę być w stanie:Sprawdź, czy operator indeksowania istnieje

  • Sprawdź, czy obiekt ma zdefiniowany operator indeksowania.
  • Jeśli jest zdefiniowany, chcę móc z niego korzystać.

Chcę zaimplementować to w poniższym kodzie. Kod zawiera obiekt (MyObject), który oferuje sposób przechodzenia przez tablicę wielowymiarową lub powiązany zestaw tabel mieszających. Powinien także zapobiegać podawaniu błędów, jeśli węzeł w żądanej ścieżce nie istnieje. Część że nie mogę dowiedzieć się, jest skomentował udział w kodzie:

public class MyObject 
{ 
    private object myObject = null; 

    public MyObject() 
    { 
    } 

    public MyObject(object value) 
    { 
     myObject = value; 
    } 

    public void setValue(object value) 
    { 
     myObject = value; 
    } 

    public object getValue() 
    { 
     return myObject; 
    } 

    public object this[string key] 
    { 
     get 
     { 
      if (myObject == null) 
      { 
       return new MyObject(null); 
      } 
      else 
      { 
       // determine what of type/class myObject is and if it has indexing operators defined 
       // if defined, access them and return the result 
       // else return null. 
      } 
     } 
     set 
     { 
      if (myObject == null) 
      { 
       // do nothing (or throw an exception); 
      } 
      else{ 
       // determine what of type/class myObject is 
       // determine if that type/class has indexing operators defined 
       // if defined, access them and set the result there 
       // else do nothing (or throw an exception). 
      } 
     } 
    } 
} 

To jest to, co chcę osiągnąć:

 // given these variables: 
     string loremIpsumString = "lorem ipsum dolor sit amet"; 
     int[] digits = new int[10]; 
     for (int i = 0; i <= 3; i++) digits[i] = i; 
     Hashtable outerHashtable = new Hashtable(); 
     Hashtable innerHashtable = new Hashtable(); 
     innerHashtable.Add("contents", "this is inside"); 
     outerHashtable.Add("outside", "this is outside"); 
     outerHashtable.Add("inside", innerHashtable); 

     // I can already print this: 
     Response.Write( loremIpsumString ); // prints "lorem ipsum dolor sit amet" 
     Response.Write( digits[0] ); // prints "0" 
     Response.Write( digits[1] ); // prints "1" 
     Response.Write( digits[2] ); // prints "2" 
     Response.Write( outerHashtable["outside"] ); // prints "this is outside" 
     Response.Write( ((Hashtable)outerHashtable["inside"])["contents"] ); // prints "this is outside" 

     // But I want to be to do it this way: 
     MyObject myObject; 

     myObject = new MyObject(loremIpsumString); 
     Response.Write( myObject.getValue() ); // prints "lorem ipsum dolor sit amet" 
     Response.Write( myObject["unexistant"].getValue() ); // prints nothing/null 
     myObject = new MyObject(digits); 
     Response.Write( myObject[0].getValue() ); // prints "0" 
     Response.Write( myObject[1].getValue() ); // prints "1" 
     Response.Write( myObject[2].getValue() ); // prints "2" 
     myObject = new MyObject(outerHashtable); 
     Response.Write( myObject["outside"].getValue() ); // prints "this is outside" 
     Response.Write( myObject["inside"]["contents"].getValue() ); // prints "this is inside" 
     Response.Write( myObject["unexistant"].getValue() ); // prints nothing/null 
     Response.Write( myObject["unexistant"]["unexistant"]["unexistant"].getValue() ); // prints nothing/null 
+0

Ok, teraz to widzę. Przepraszam, że nie przeczytałem kilku pierwszych odczytów przez –

Odpowiedz

7

można najpierw sprawdzić, czy to dziedziczenie IList na pokrycie (generic) Lists i Array. Jeśli nie można użyć PropertyInfo.GetIndexParameters aby sprawdzić, czy to ma podziałowe zamiast:

get 
{ 
    if (myObject == null) 
    { 
     return null; 
    } 
    else 
    { 
     // not sure which index(es) you want 
     int index = 0; 
     Type t = myObject.GetType(); 
     if (typeof(IList).IsAssignableFrom(t)) 
     { 
      IList ilist = (IList)myObject; 
      return ilist[index]; 
     } 
     else 
     { 
      var indexer = t.GetProperties() 
       .Where(p => p.GetIndexParameters().Length != 0) 
       .FirstOrDefault(); 
      if (indexer != null) 
      { 
       object[] indexArgs = { index }; 
       return indexer.GetValue(myObject, indexArgs); 
      } 
      else 
       return null; 
     } 
    } 
} 

DEMO (z string który ma indexer aby uzyskać dostęp do znaków)

+0

Pojawił się ten błąd w .Where(): "System.Array" nie zawiera definicji "Gdzie" i bez metody rozszerzenia "Gdzie" akceptuje pierwszy argument typu " System.Array "można znaleźć (czy brakuje dyrektywy użycia lub odniesienia do zestawu?) –

+0

@ nl-x: I potrzebujesz' using System.Linq; '!. –

+0

Ah, tymczasem zacząłem (krok po kroku), aby zrozumieć, co mówi, i naprawdę próbuję to z prostą pętlą. Może powinienem po prostu użyć Linq? –

1

można przetestować jeśli obiekt jest słownikiem

public object this[string key] 
{ 
    get 
    { 
     var dict = myObject as IDictionary; 
     if (dict == null) { 
      return null; 
     } 
     if (dict.Contains(key)) { 
      return dict[key]; 
     } 
     return null; 
    } 
    set 
    { 
     var dict = myObject as IDictionary; 
     if (dict != null) { 
      dict[key] = value; 
     } 
    } 
} 

Uwaga: Jeśli masz kontrolę nad słowniku typu użyć, a następnie wolą Dictionary<string,object> ponad Hashtable. Jego poręczna metoda pozwala bezpiecznie uzyskać do niej dostęp bez uprzedniego wywołania Contains i tym samym oszczędza dostępu do niego dwukrotnie. Z tego powodu należy odrzucić do Dictionary<string,object> zamiast IDictionary.

var dict = myObject as Dictionary<string,object>; 
if (dict == null) { 
    return null; 
} 
object result; 
dict.TryGetValue(key, out result); // Automatically sets result to null 
            // if an item with this key was not found. 
return result; 
+0

Próbowałem wejść na tę ścieżkę wcześniej, ale poniosłem porażkę. Spróbuję ponownie! –

0

Dla innych poszukujących odpowiedzi. Oto, co zrobiłem z pomocą @TimSchmelter.

To jest kod, który zaimplementowałem w get {}, którego użyłem w kodzie u góry tego ekranu, gdzie na górze tego ekranu get {} właśnie zawierał komentarze.

get 
{ 
    if (myObject == null) 
     return new MyObject(null); 
    object returnValue = null; 
    bool foundReturnValue = false; 
    object[] indexArgs = { key }; 
    Type myObjectType = myObject.GetType(); 
    if (typeof(IList).IsAssignableFrom(myObjectType)) 
    { 
     try 
     { 
      returnValue = ((IList)myObject)[((int)key)]; 
      foundReturnValue = true; 
     } 
     catch (Exception) { } 
    } 
    if (!foundReturnValue) 
    { 
     foreach (PropertyInfo property in myObjectType.GetProperties()) 
     { 
      ParameterInfo[] indexParameters = property.GetIndexParameters(); 
      foreach (ParameterInfo indexParameter in indexParameters) 
      { 
       if (indexParameter.ParameterType.IsAssignableFrom(key.GetType())) 
       { 
        try 
        { 
         returnValue = property.GetValue(myObject, indexArgs); 
         foundReturnValue = true; 
        } 
        catch (Exception) { } 
       } 
       if (foundReturnValue == true) 
        break; 
      } 
      if (foundReturnValue == true) 
       break; 
     } 
    } 
    return new MyObject(returnValue); 
}