根据https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-8.0/default-interface-methods 可以使用以下语法显式调用基于接口的实现。
base(IInterfaceType).Method();
但这似乎尚未实现。
是否有解决方法(例如反射)来实现这一目标?
示例代码来说明问题
interface IA
{
void M()
{
Console.WriteLine("IA.M");
}
}
interface IB : IA
{
void IA.M()
{
Console.WriteLine("IB.M");
}
}
interface IC : IA
{
void IA.M()
{
Console.WriteLine("IC.M");
}
}
class D : IA, IB, IC
{
public void M()
{
// base(IB).M(); Is not yet supported apparently
((IB)this).M(); // Throws stack overflow
}
}
class Program
{
static void Main(string[] args)
{
D d = new D();
d.M();
}
}
答案 0 :(得分:4)
问题中的链接指向复制的from the proposal document in Github提案的版本
结论
剪切C#8的base()语法。我们打算在下一个主要版本中重新使用它。
设计会议文档解释说,如果没有运行时支持(无法及时提供),则该实现最多只能对C#有效,而对VB.NET则不可行。
如果运行时不存在B.M,则将调用A.M()。对于base()和interfaces,运行时不支持此功能,因此调用将引发异常。我们想在运行时中添加对此的支持,但是发布此版本太昂贵了。
我们有一些解决方法,但是它们没有我们想要的行为,也不是首选的代码生成器。尽管不是我们想要的那样,我们对C#的实现还是可行的,但是VB的实现会困难得多。而且,VB的实现要求接口的实现方法必须是公开的API表面。
至于无限递归,
public void M()
{
((IB)this).M(); // Throws stack overflow
}
基本上是
public void M()
{
M(); // Throws stack overflow
}
通过接口调用默认接口成员的方式与显式实现接口方法的方式相同。此外,您要求在this
而不是base
上调用方法。
答案 1 :(得分:0)
有一种解决方法。
我使用GetFunctionPointer
警告不要使用此代码
static class BaseInterfaceInvocationExtension
{
private static readonly string invalidExpressionMessage = "Invalid expression.";
public static void Base<TInterface>(this TInterface owner, Expression<Action<TInterface>> selector)
{
if (selector.Body is MethodCallExpression methodCallExpression)
{
MethodInfo methodInfo = methodCallExpression.Method;
string name = methodInfo.DeclaringType.FullName + "." + methodInfo.Name;
Type type = owner.GetType();
InterfaceMapping interfaceMapping = type.GetInterfaceMap(typeof(TInterface));
var map = interfaceMapping;
var interfaceMethod = map.InterfaceMethods.First(info =>
info.Name == name);
var functionPointer = interfaceMethod.MethodHandle.GetFunctionPointer();
var x = methodCallExpression.Arguments.Select(expression =>
{
if (expression is ConstantExpression constantExpression)
{
return constantExpression.Value;
}
var lambda = Expression.Lambda(Expression.Convert(expression, expression.Type));
return lambda.Compile().DynamicInvoke();
}).ToArray();
Type actionType = null;
if (x.Length == 0)
{
actionType = typeof(Action);
}else if (x.Length == 1)
{
actionType = typeof(Action<>);
}
else if (x.Length == 2)
{
actionType = typeof(Action<,>);
}
var genericType = actionType.MakeGenericType(methodInfo.GetParameters().Select(t => t.ParameterType).ToArray());
var instance = Activator.CreateInstance(genericType, owner, functionPointer);
instance.GetType().GetMethod("Invoke").Invoke(instance, x);
}
else
{
throw new Exception(invalidExpressionMessage);
}
}
}
class D : IA, IB, IC
{
public void M(int test)
{
this.Base<IB>(d => d.M(test));
}
}
class Program
{
static void Main(string[] args)
{
D d = new D();
d.M(12);
Console.ReadKey();
}
}
答案 2 :(得分:0)
这是一种解决方法。这不是理想的。也许会帮助某人。
class C : IB
{
public void IBM() => (this as IB).M();
}
class D : IA, IB, IC
{
private C _c = new C();
public void M()
{
_c.IBM();
}
}