2013-01-22 108 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); 
}