C# 11 引入了接口中的静态抽象成员。
但从我正在试验的情况来看,它只会强制“直接子级”实现这些“static abstract
”成员。该
static abstract
修饰符不能在 abstract class
中使用。我正在尝试做的事情的一个例子,但无法编译:
public interface IMyInterface
{
public static abstract void DoSomething();
}
public abstract class MyAbstractClass : IMyInterface
{
public static abstract void DoSomething(); //Error: Overridable method cannot be static
}
public class MyClass : MyAbstractClass
{
public static override void DoSomething() => Console.Log("Hello, World!");
}
但是它们之间没有
abstract class
,
MyClass
确实编译得很好:public class MyClass : IMyInterface
{
public static void DoSomething() => Console.Log("Hello, World!");
}
我错过了什么吗?为什么会这样呢?
我相信我已经知道我的案例的解决方法,但这种方式不会强制
MyAbstractClass
的每个孩子都实现
IMyInterface
,就像我们对常规接口成员所做的那样。public interface IMyInterface
{
public static abstract void DoSomething();
}
public abstract class MyAbstractClass
{
}
public class MyClass : MyAbstractClass, IMyInterface
{
public static void DoSomething() => Console.Log("Hello, World!");
}
static abstract
修饰符不能在
中使用。 正确。abstract class
我错过了什么吗?为什么会这样呢?
这是设计使然。
static abstract
class
类型。...因为这样的成员永远无法使用(在受约束的通用上下文之外)。static
this
引用可从中获取 vtable 引用。...因为它是 static
static
方法没有隐式
(和隐藏)this
参数)。
class SubclassA : IMyInterface
{
public static void DoSomething() => Console.WriteLine( "Explosive bolts, ten thousand volts, At a million miles an hour" );
}
class SubclassAB : SubclassA
{
public static void DoSomething() => Console.WriteLine( "Life is short and love is always over in the morning." );
}
class SubclassB : IMyInterface
{
public static void DoSomething() => Console.WriteLine( "Hot metal and methedrine." );
}
//
public void Main()
{
MyMethod( new SubclassA() );
MyMethod( new SubclassAB() );
MyMethod( new SubclassB() );
}
public void MyMethod( IMyInterface instance )
{
// At this point, how do you propose invoking `DoSomething`? (without using reflection)
// ...see the problem?
}
但是,
interface
类型
do支持
static abstract
成员,但这只是因为它们在泛型方法约束的上下文中很有用,因为它允许泛型代码为非虚拟的调用站点指定方法: JIT/运行时实例化一个通用方法,它发出static方法调用,而不是基于vtable的调用。 (对于 Swift 用户来说,这有点像
protocol
类型与 C# 或 Java interface
类型不同,因为
protocol
支持对值类型的非装箱调用,而(在非泛型中)方法)C# interface
类型始终被视为引用类型,但无论如何)。
我相信我已经知道我的案例的解决方法,但这种方式并不能强迫
MyAbstractClass
的每个孩子都实施IMyInterface
听起来你正在使用接口类型作为一种linter
,以保证一组class
类型都遵循某种通用的编码约定并实现一些通用的成员集(在此情况下,static
成员),即使您从未在程序中的任何地方使用该
interface
- 但这不是 C# 中 interface
类型的用途。
然而,如果您将
MyMethod
设为泛型方法并使用 IMyInterface
作为约束,那么它就会变得有用,因为
now您可以通过使用类型参数作为类型名称来调用
static
方法:
public void MyGenericMethod<T>( T instance )
where T : IMyInterface
{
T.DoSomething();
}
public void Main()
{
GenericMethod<SubclassA>(); // Will print "Explosive bolts, ten thousand volts, At a million miles an hour"
GenericMethod<SubclassAB>(); // <-- This actually behaves the same as SubclassA.
GenericMethod<SubclassB>(); // Will print "Hot metal and methedrine."
}
...尽管使用 SubclassAB
进行的调用与
SubclassA
的行为相同,因为使用
SubclassAB
,即使 T.DoSomething()
存在,对 SubclassA.DoSomething()
的调用也会路由到 SubclassAB.DoSomething()
。...我不知道为什么这不起作用(还)。 原始提案文件只是为此添加了“TBD”,奇怪的是我找不到Roslyn 存储库中提交的任何相关错误
,所以当我发现时我会更新这个答案。
我想你可以说 T : BaseClass
T : IInterface
约束之间没有区别 - 至少就这段代码(如下)可以说
应该可以工作,但事实并非如此(
CS0704)
public class BaseClass
{
public static void DoSomething() => Console.WriteLine( "Strange men rent strange flowers" );
}
public class DerivedClass : BaseClass
{
public static void DoSomething() => Console.WriteLine( "Mundane by day inane at night" );
}
public static void Main()
{
GenericMethod<AbstractClass>(); // Should print "Strange men rent strange flowers"
GenericMethod<DerivedClass >(); // Should print "Mundane by day inane at night"
}
public static void GenericMethod<T>()
where T : BaseClass
{
Type t = typeof(T);
T.DoSomething(); // CS0704
}
public interface IMyInterface
{
public static abstract void DoSomething();
}
//A call to DoSomething() will be specific to
//the class that derives from MyAbstractClass.
public abstract class MyAbstractClass : IMyInterface
{
public static void DoSomething()
{
}
}
public class MyClass : MyAbstractClass
{
public new static void DoSomething()
{
Console.WriteLine("Hello from MyClass.");
}
}
public class MyClass2 : MyAbstractClass
{
public new static void DoSomething()
{
Console.Writeline("Hello from MyClass2!");
}
}