【问题标题】:Check if indexing operator exists检查索引运算符是否存在
【发布时间】:2013-01-22 16:04:37
【问题描述】:

我希望能够:

  • 检查对象是否定义了索引运算符。
  • 如果它被定义了,我希望能够使用它。

我想在下面的代码中实现这一点。 该代码包含一个对象 (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

【问题讨论】:

  • 好的,我现在明白了。抱歉,我没有阅读前几篇文章

标签: c# multidimensional-array


【解决方案1】:

您可以先检查它是否继承 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 可以访问字符)

【讨论】:

  • @nl-x:你需要一个using System.Linq;!。
  • @nl-x:Linq 通常更适合 redable。但是使用你可以/想使用的任何东西。查询不是我回答的重要部分。是GetIndexParameters().Lengthindexer.GetValue
  • @nl-x:编辑了我的答案以提供一种方法,该方法也适用于数组和列表,因为它们都继承自 IList
  • @TimSchmelter :尽管您的解决方案实际上对我的问题有所帮助,但似乎并不是问题的真正答案;是如何知道索引运算符是否存在以及如何使用它们。当然必须有一种方法来确定对象/类是否设置了索引运算符(方括号 [])?为什么需要 if-array-iList-else-GetIndexParameters 解决方案? (不过,我会将您的答案标记为已接受)
  • @nl-x:数组/列表没有/使用索引器来访问值。索引器只是使用与数组类似的语法,但实际上它是一个属性。这就是为什么所有集合的 GetIndexParameters.Length 都是 0 的原因。如上所示,无需反射即可访问数组/列表的值非常简单有效。这就是为什么我首先检查它是否可以转换为 ILIst 这是所有集合的基本接口(甚至是通用的)。
【解决方案2】:

你可以测试对象是否是字典

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&lt;string,object&gt; 而不是Hashtable。其方便的方法TryGetValue 允许您无需先调用Contains 就可以安全地访问它,从而避免您访问它两次。当然,您将转换为 Dictionary&lt;string,object&gt; 而不是 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;

【讨论】:

  • 我之前尝试过这条路,但惨遭失败。我再试一次!
【解决方案3】:

对于寻找答案的其他人。这是我在 @TimSchmelter 的帮助下完成的。

这是我在 get{} 中实现的代码,我在此屏幕顶部的代码中使用了该代码,在此屏幕顶部的 get{} 中只包含 cmets。

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

【讨论】:

    猜你喜欢
    • 2021-07-22
    • 2012-11-30
    • 2015-09-16
    • 1970-01-01
    • 2013-05-28
    • 2010-09-20
    • 2016-05-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多