通过抽象类在接口中静态抽象成员?

问题描述 投票:0回答:2

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!");
}

	
c# inheritance interface abstract-class c#-11.0
2个回答
1
投票
但是根据我的实验,它只会强制直接子级实现这些静态抽象成员。该
static abstract

修饰符不能在

abstract class
中使用。

正确。

我错过了什么吗?为什么会这样呢?

这是设计使然。
  • ...因为没有理由向
  • static abstract
  • 成员介绍
    class
    类型。
    ...因为这样的成员永远无法使用(在受约束的通用上下文之外)。
  • ...因为
  • static
  • 成员不是通过虚拟调用(vtable 查找)调用的,因为没有
    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!");
    }
}

-1
投票
© www.soinside.com 2019 - 2024. All rights reserved.