从MethodInfo检测索引器

时间:2019-01-03 15:11:38

标签: c# expression-trees system.reflection

给出以下代码:

var dict = new Dictionary<string,string>() {
    {"",""}
};
Expression<Func<string>> expr = () => dict[""];

expr.Body返回MethodCallExpression的实例,该实例的Method属性返回get__Item MethodInfo

似乎没有什么信息可用来检测被调用的方法(get__Item)是索引器的基础方法。

如何检测给定的MethodInfo引用了索引器的基础方法?

这不是Indentifying a custom indexer using reflection in C#的副本,因为(如标题,评论和this answer中所述)我没有PropertyInfo,只有{{1 }};链接的问题是询问有关将特定的MethodInfo标识为索引器。

我正在尝试将表达式树映射到Roslyn PropertyInfo,并且上面的表达式树不应映射为:

SyntaxNode

或:

() => dict.Item("")

但是,作为原始源代码:

() => dict.get__Item("")

1 个答案:

答案 0 :(得分:0)

您可以通过检查类型来确定哪个属性(如果有)是索引器。 (您正在查看的是方法,而不是属性,但我会介绍的。)

来自the DefaultMemberAttribute reference

  

C#编译器会在任何包含索引器的类型上发出DefaultMemberAttribute。

所以问题变成了

  • 调用该方法的类型是否具有该属性?
  • 是您正在为此检查getter或setter的方法 财产?

如果两者的答案均为“是”,则该方法将访问索引器属性。

以下是一些功能。不好看我不是在问你的理由是否合理。我只是觉得很有趣。

public static class ReflectionExtensions
{
    public static bool IsIndexerPropertyMethod(this MethodInfo method)
    {
        var declaringType = method.DeclaringType;
        if (declaringType is null) return false;
        var indexerProperty = GetIndexerProperty(method.DeclaringType);
        if (indexerProperty is null) return false;
        return method == indexerProperty.GetMethod || method == indexerProperty.SetMethod;
    }

    private static PropertyInfo GetIndexerProperty(this Type type)
    {
        var defaultPropertyAttribute = type.GetCustomAttributes<DefaultMemberAttribute>()
            .FirstOrDefault();
        if (defaultPropertyAttribute is null) return null;
        return type.GetProperty(defaultPropertyAttribute.MemberName, 
            BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
    }
}

这些并不是最出色的单元测试,但是无论如何我都希望包含它们。

[TestClass]
public class ReflectionExtensionTests
{
    [TestMethod]
    public void DetectsIndexer()
    {
        var dict = new Dictionary<string, string>() {
            {"",""}
        };
        Expression<Func<string>> expr = () => dict[""];
        var method = (expr.Body as MethodCallExpression).Method;
        Assert.IsTrue(method.IsIndexerPropertyMethod());
    }

    [TestMethod]
    public void DetectsNotIndexer()
    {
        var dict = new Dictionary<string, string>() {
            {"",""}
        };
        Expression<Action<string, string>> expr = (s, s1) => dict.Add(s, s1);
        var method = (expr.Body as MethodCallExpression).Method;
        Assert.IsFalse(method.IsIndexerPropertyMethod());
    }

    [TestMethod]
    public void DetectsRenamedIndexer()
    {
        var myClass = new ClassWithRenamedIndexer();
        Expression<Func<int>> expr = () => myClass[2];
        var method = (expr.Body as MethodCallExpression).Method;
        Assert.IsTrue(method.IsIndexerPropertyMethod());
    }

    class ClassWithRenamedIndexer
    {
        [IndexerName("blarg")]
        public int this[int index]    // Indexer declaration  
        {
            get { return 1; }
        }
    }
}