2013-01-22 31 views
5

我希望能夠到:檢查索引操作符存在

  • 檢查對象是否定義的索引操作。
  • 如果已定義,我希望能夠使用它。

我想在下面的代碼中實現它。 該代碼包含一個對象(MyObject),該對象提供了遍歷多維數組或鏈接的哈希表集的方法。如果請求的路徑中的節點不存在,它也應該防止給出錯誤。 我想不通的部分是在代碼中的註釋部分:

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). 
      } 
     } 
    } 
} 

這就是我要完成:

 // 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

好的,我明白了。對不起,我沒有按照前幾個通過 –

回答

7

您可以先檢查它是否繼承IList覆蓋(通用)Lists和數組。如果沒有,你可以使用PropertyInfo.GetIndexParameters來檢查它是否有一個索引來代替:

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(用string它有一個indexer訪問字符)

+0

讀取我讀到這個錯誤.Where():'System.Array'不包含'Where'的定義和沒有擴展方法'Where'接受類型的第一個參數'可以找到System.Array'(你是否缺少使用指令或程序集引用?) –

+0

@ nl-x:並且你需要'使用System.Linq;'!. –

+0

啊,與此同時我已經開始(一點一滴地)瞭解它說了什麼,並且確實試圖通過一個簡單的循環。也許我應該只使用Linq? –

1

您可以測試如果對象是一個字典

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

注:如果您在字典類型使用該控件,然後喜歡Dictionary<string,object>超過Hashtable。其方便的方法TryGetValue允許您安全地訪問它,而無需先撥打Contains,從而避免您訪問它兩次。因爲你會投到Dictionary<string,object>而不是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

我以前試過走這條路,但慘敗了。我會再嘗試! –

0

對於正在尋找答案的其他人。這是我在@TimSchmelter的幫助下完成的。

因此,這是我在get {}中實現的代碼,我在此屏幕頂部的代碼中使用,在此屏幕的頂部,get {}僅包含註釋。

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