Reputation: 15357
Given the following code:
var dict = new Dictionary<string,string>() {
{"",""}
};
Expression<Func<string>> expr = () => dict[""];
expr.Body
returns an instance of MethodCallExpression
, whose Method
property returns the get__Item
MethodInfo
.
There doesn't seem to be any information which I can use to detect that the method being called (get__Item
) is the method underlying an indexer.
How can I detect that a given MethodInfo
refers to the method underlying an indexer?
This is not a duplicate of Indentifying a custom indexer using reflection in C#, because (as noted in the title, the comments, and this answer) I don't have a PropertyInfo
, only a MethodInfo
; and the linked question is asking about identifying a specific PropertyInfo
as the indexer.
I am trying to map expression trees to Roslyn SyntaxNode
s, and the above expression tree should not be mapped as:
() => dict.Item("")
or:
() => dict.get__Item("")
but rather, as the original source code:
() => dict[""]
Upvotes: -1
Views: 395
Reputation: 29252
Update: I can't delete this because it's the accepted answer. It worked for someone but I'd check out the other answer.
You can determine which property (if any) is an indexer by inspecting the type. (You're looking at a method, not a property, but I'll get to that.)
From the DefaultMemberAttribute
reference
The C# compiler emits the DefaultMemberAttribute on any type containing an indexer.
So the question becomes
If the answer to both is "yes" then the method accesses an indexer property.
Here are a few functions. This isn't pretty. I'm not questioning whether or not your reason makes sense. I just found it interesting.
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);
}
}
These are not the most glorious unit tests, but I like to include them anyway.
[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; }
}
}
}
Upvotes: -1