c# - 通过反射从对象获取索引值

标签 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
}

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

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

private object[] GetIndexArray(SOP sop)

但我不知道如何调用 this 属性。 对象实例可以是任何东西,字符串字典、...

有人知道如何解决这个问题吗?

编辑: 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()
}

编辑2: 在 C# 中,每个 getter 和 setter 都可以通过反射作为方法来调用。有没有办法获取“this”属性的方法?如果可以的话,可以通过调用方法来解决问题。

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

最佳答案

我决定重新制作这篇文章,因为我的上一篇文章没有正确地完成它应该做的事情。

要检查对象上有哪些索引器,您可以使用以下命令,这将

  • 当对象为 null 时返回 null
  • 未找到索引器时返回空 IList
  • 返回包含找到的索引器的 MethodInfo 列表

检查它的技巧是检查属性是否有任何 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;
}

这适用于列表、字典、字符串、带索引器的对象、使用 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()
    {
    }
}

对于其余的,这是一项很好的研究,感谢您的提问!

关于c# - 通过反射从对象获取索引值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27469240/

相关文章:

java - 我如何找出 lambda 适用于哪种方法?

python - 在 Pytorch 中高级索引以摆脱嵌套的 for 循环

MySQL ORDER BY 导致 LEFT JOIN 速度极度减慢

c++ - 如何向我的应用程序添加搜索功能

c# - 从列表中的图片框进行碰撞检测 C#

c# - 如何反序列化对结构等效项的引用集合?

c# - CQRS 写入端 DDD 中的时间序列/时间数据

c# - 如何更新 ComboBox

c# - 如何释放通过Reflection加载的DLL?

c# - 将对象转换为 Task<T> 并从类型为 Type 的变量设置 T