从反射对象获取索引值

时间:2014-12-14 12:21:54

标签: c# reflection indexing

我遇到了问题,我不知道如何通过反射调用对象实例的this属性。

我有以下方法:

public object GetValue(SOP sop, object value)
{
    // 1. find the this getter/setter method for the value parameter
    // 2. Invoke the method and pass the result of GetIndexArray(sop) as a parameter
    // 3. return the result of the method
}

应该调用this - 实例的value属性并返回属性返回的值。 问题是,我不知道value - 实例的类型,它作为参数传递。

应该传递给this属性的索引通过以下方法给出:

private object[] GetIndexArray(SOP sop)

但我不知道如何拨打this - 财产。 object - 实例可以是任何内容,stringDictionary,...

有人有想法,如何解决问题?

修改 GetValue方法应该执行以下任务,但动态反思:

public object GetValue(SOP sop, object value)
{
    // Non relfection, lets say 'value' is a Dicitionary<string, string> 
    // return value["key"];
    // The type of 'value' is unknown, and the index-parameter (the keys) are accessable over GetIndexArray()
}

EDIT2: 在c#中,每个getter和setter都可以通过反射作为方法调用。有没有办法,为&#34;这个&#34;属性?如果可能的话,可以通过调用mesthod来解决问题。

调用GetValue方法

object pInst = parentInstance.GetType().GetProperty(VariableName, System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic).GetValue(parentInstance, null);

            var indexChldren = FindChildrenOfType<IndexNode>();

            if (indexChldren.Count > 0)
            {
                pInst = indexChldren[0].GetValue(sop, pInst);
            }

1 个答案:

答案 0 :(得分:1)

我决定重新发布这个帖子,因为我之前的帖子并没有正确地做它应该做的事情。

要检查对象上的索引器,可以使用以下命令

  • 当对象为空时返回null
  • 未找到索引器时返回空IList
  • 使用找到的索引器
  • 返回MethodInfos列表

检查它的技巧是检查属性是否有GetIndexParameters();

public IList<MethodInfo> GetIndexProperties(object obj)
{
    if (obj == null)
    {
        return null;
    }
    var type = obj.GetType();
    IList<MethodInfo> results = new List<MethodInfo>();

    try
    {
        var props = type.GetProperties(System.Reflection.BindingFlags.Default | 
            System.Reflection.BindingFlags.Public | 
            System.Reflection.BindingFlags.Instance);

        if (props != null)
        {
            foreach (var prop in props)
            {
                var indexParameters = prop.GetIndexParameters();
                if (indexParameters == null || indexParameters.Length == 0)
                {
                    continue;
                }
                var getMethod = prop.GetGetMethod();
                if (getMethod == null)
                {
                    continue;
                }
                results.Add(getMethod);
            }
        }

    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }

    return results;
}

这适用于List,Dictionary,string,带索引器的对象,使用IndexerNameAttribute定义的索引器

作为一个例子,我使用这个MainMethod来尝试几种可能性

object[] exampleHayStack = new object[] {
    "This is a test of an indexer", 
    new TestIndexer(),
    null,
    string.Empty,
    new ClassIndexer(),
    new Dictionary<string, string>() { { "key", "value" } },
    new List<string>() { "A", "B", "C", "D", "E", "F", "G" } };

ClassIndexer myIndexer = new ClassIndexer();

foreach (var obj in exampleHayStack)
{
    var methods = myIndexer.GetIndexProperties(obj);
    if (methods == null || methods.Count == 0)
    {
        Console.WriteLine("{0} doesn't have any indexers", obj);
        continue;
    }
    Console.WriteLine("Testing {0}", obj);
    foreach (MethodInfo mi in methods)
    {
        IList<object> indexParams = new List<object>();
        var requiredParams = mi.GetParameters();
        foreach (var par in requiredParams)
        {
            indexParams.Add(myIndexer.ParamForObject(obj, par));
        }
        try
        {
            var result = mi.Invoke(obj, indexParams.ToArray());
            Console.WriteLine("Result of requesting ({0}) = {1}", string.Join(",", indexParams), result);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }
}
Console.ReadLine();

然后导致:

Testing This is a test of an indexer
Result of requesting (21) = i
Testing TestReflection.Program+TestIndexer
Result of requesting (53) = 5
Result of requesting (Key) = Key item
 doesn't have any indexers
Testing
Exception has been thrown by the target of an invocation.
TestReflection.Program+ClassIndexer doesn't have any indexers
Testing System.Collections.Generic.Dictionary`2[System.String,System.String]
Result of requesting (key) = value
Testing System.Collections.Generic.List`1[System.String]
Result of requesting (5) = F

您可以在此处找到ClassIndexer的完整实现,它包含一个额外的方法来获取可能的键值(但是您已经拥有的键值)

public class ClassIndexer
{
    Random pNext = new Random();

    public IList<MethodInfo> GetIndexProperties(object obj)
    {
        if (obj == null)
        {
            return null;
        }
        var type = obj.GetType();
        IList<MethodInfo> results = new List<MethodInfo>();

        try
        {
            var props = type.GetProperties(System.Reflection.BindingFlags.Default |
                System.Reflection.BindingFlags.Public |
                System.Reflection.BindingFlags.Instance);

            if (props != null)
            {
                foreach (var prop in props)
                {
                    var indexParameters = prop.GetIndexParameters();
                    if (indexParameters == null || indexParameters.Length == 0)
                    {
                        continue;
                    }
                    var getMethod = prop.GetGetMethod();
                    if (getMethod == null)
                    {
                        continue;
                    }
                    results.Add(getMethod);
                }
            }

        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }

        return results;
    }

    public object ParamForObject(object obj, ParameterInfo pi)
    {
        if (obj is IDictionary)
        {
            int maxNumber = ((IDictionary)obj).Keys.Count;
            if (pi.ParameterType.Equals(typeof(int)))
            {
                return pNext.Next(maxNumber);
            }
            if (pi.ParameterType.Equals(typeof(string)))
            {
                int target = pNext.Next(maxNumber);
                foreach (var key in ((IDictionary)obj).Keys)
                {
                    target--;
                    if (target <= 0)
                    {
                        return key;
                    }
                }
                return null;
            }
        }
        if (obj is string)
        {
            if (pi.ParameterType.Equals(typeof(int)))
            {
                return pNext.Next((obj as string).Length);
            }
        }
        if (obj is IList)
        {
            return pNext.Next(((IList)obj).Count);
        }
        if (pi.ParameterType.Equals(typeof(string)))
        {
            return "Key";
        }
        if (pi.ParameterType.Equals(typeof(int)))
        {
            return pNext.Next(100);
        }
        return null;
    }

    public ClassIndexer()
    {
    }
}

对于其他人来说,这是一项很好的研究,谢谢你的问题!