代码之家  ›  专栏  ›  技术社区  ›  Zev Spitz

从MethodInfo中检测索引器[重复]

  •  -1
  • Zev Spitz  · 技术社区  · 6 年前

    给定以下代码:

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

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

    似乎没有任何信息可以用来检测正在调用的方法( 获取项目 )是索引器的基础方法。

    我怎样才能检测到一个给定的 引用索引器的基础方法?

    Indentifying a custom indexer using reflection in C# ,因为(如标题、评论和 this answer )我没有电话 PropertyInfo ,只有一个 ; 与此相关的问题是关于确定一个特定的 物业资讯 作为索引器。

    SyntaxNode s、 上述表达式树不应映射为:

    () => dict.Item("")
    

    () => dict.get__Item("")
    

    () => dict[""]
    
    1 回复  |  直到 6 年前
        1
  •  0
  •   Scott Hannen    6 年前

    您可以通过检查类型来确定哪个属性(如果有)是索引器。(您看到的是一个方法,而不是一个属性,但我会继续讲下去。)

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