从 MethodInfo 检测索引器
Detect indexer from MethodInfo
给定以下代码:
var dict = new Dictionary<string,string>() {
{"",""}
};
Expression<Func<string>> expr = () => dict[""];
expr.Body
returns MethodCallExpression
的实例,其 Method
属性 returns get__Item
MethodInfo
.
似乎没有任何信息可以用来检测被调用的方法 (get__Item
) 是索引器的基础方法。
如何检测给定的 MethodInfo
引用了索引器的底层方法?
这不是 Indentifying a custom indexer using reflection in C#, because (as noted in the title, the comments, and 的副本)我没有 PropertyInfo
,只有 MethodInfo
;链接的问题是询问如何将特定的 PropertyInfo
识别为索引器。
我正在尝试将表达式树映射到 Roslyn SyntaxNode
s,上面的表达式树不应映射为:
() => dict.Item("")
或:
() => dict.get__Item("")
而是作为原始源代码:
() => dict[""]
您可以通过检查类型来确定哪个 属性(如果有)是索引器。 (您正在查看一种方法,而不是 属性,但我会谈到它。)
来自the DefaultMemberAttribute
reference
The C# compiler emits the DefaultMemberAttribute on any type containing an indexer.
所以问题就变成了
- 调用该方法的类型是否具有该属性?
- 是您检查 getter 或 setter 的方法
属性?
如果两者的答案都是 "yes",则该方法访问索引器 属性。
这里有几个函数。这不漂亮。我不是在质疑你的理由是否有道理。我只是觉得它很有趣。
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; }
}
}
}
给定以下代码:
var dict = new Dictionary<string,string>() {
{"",""}
};
Expression<Func<string>> expr = () => dict[""];
expr.Body
returns MethodCallExpression
的实例,其 Method
属性 returns get__Item
MethodInfo
.
似乎没有任何信息可以用来检测被调用的方法 (get__Item
) 是索引器的基础方法。
如何检测给定的 MethodInfo
引用了索引器的底层方法?
这不是 Indentifying a custom indexer using reflection in C#, because (as noted in the title, the comments, and PropertyInfo
,只有 MethodInfo
;链接的问题是询问如何将特定的 PropertyInfo
识别为索引器。
我正在尝试将表达式树映射到 Roslyn SyntaxNode
s,上面的表达式树不应映射为:
() => dict.Item("")
或:
() => dict.get__Item("")
而是作为原始源代码:
() => dict[""]
您可以通过检查类型来确定哪个 属性(如果有)是索引器。 (您正在查看一种方法,而不是 属性,但我会谈到它。)
来自the DefaultMemberAttribute
reference
The C# compiler emits the DefaultMemberAttribute on any type containing an indexer.
所以问题就变成了
- 调用该方法的类型是否具有该属性?
- 是您检查 getter 或 setter 的方法 属性?
如果两者的答案都是 "yes",则该方法访问索引器 属性。
这里有几个函数。这不漂亮。我不是在质疑你的理由是否有道理。我只是觉得它很有趣。
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; }
}
}
}