Open sw1nn4 opened 4 years ago
The problem occurs for all explicitly implemented properties In this case, the name does not start with get
because it will look like Full.Name.Of.Interface.Type.get_Property
.
reproduction:
interface IInterface
{
int Property { get; }
}
class Class : IInterface
{
int IInterface.Property => -6; // crash
public int Property => -6; // no crash
}
class Program
{
static void Main()
{
var t = typeof(Class);
foreach (var method in t.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
{
Console.WriteLine($"Name: '{method.Name}'");
Console.WriteLine(method.GetPropertyFromMethod(t));
}
}
}
My first guess would be look for the last dot in Name first, and only then check for get
prefix. Also, the length<4
condition must be revisited.
Naive attempt to fix the method:
public static PropertyInfo GetPropertyFromMethod(this MethodInfo method, Type implementingType)
{
if (!method.IsSpecialName)
{
return null;
}
var fullName = method.Name.AsSpan();
var lastPeriod = fullName.LastIndexOf('.');
var interfaceNameWithPeriod = fullName[..(lastPeriod + 1)];
var name = fullName[(lastPeriod + 1)..];
if (name.Length < 4)
{
return null;
}
var isGetMethod = name.StartsWith("get", StringComparison.InvariantCulture);
var returnType = isGetMethod ? method.ReturnType : method.GetParameterTypes().Last();
var indexerTypes = isGetMethod ? method.GetParameterTypes() : method.GetParameterTypes().SkipLast(1);
var propertyName = $"{interfaceNameWithPeriod}{name[4..]}";
return implementingType.GetProperty(propertyName, DefaultBindingFlags, null, returnType, indexerTypes.ToArray(), null);
}
ExtensionsForMethodInfo.GetPropertyFromMethod(Type t)
is throwing an exception when called on a property getter.The method name is returned as "IGenericStateSetter`1[Boolean].get_Value", therefore the
substring(0,3)
does not equal "get", as expected. Since it's a property gettermethod.GetParameterTypes()
returns an empty list, so the call toLast()
throws an invalid operation exception.I'm not trying to intercept the method, but I presume a check is being performed as to whether it should be intercepted or not. I'm also using a Ninject.MockingKernel to create test mocks for any missing bindings. (The issue happens regardless of which mocking framework is used, I think they all use Castle.Proxies)
I don't believe there's any way to specify not to try intercepting an activation?
Stack trace: