简体   繁体   English

如何在接口上实现 static 方法?

[英]How can I implement static methods on an interface?

I have a 3rd party C++ DLL that I call from C#.我有一个来自 C# 的第三方 C++ DLL。

The methods are static.方法是 static。

I want to abstract it out to do some unit testing so I created an interface with the static methods in it but now my program errors with:我想把它抽象出来做一些单元测试,所以我创建了一个带有 static 方法的接口,但现在我的程序错误:

The modifier 'static' is not valid for this item修饰符“静态”对此项目无效

MyMethod cannot be accessed with an instance reference; qualify it with a type name instead

How can I achieve this abstraction?我怎样才能实现这种抽象?

My code looks like this我的代码看起来像这样

private IInterfaceWithStaticMethods MyInterface;

public MyClass(IInterfaceWithStaticMethods myInterface)
{
  this.MyInterface = myInterface;
}

public void MyMethod()
{
  MyInterface.StaticMethod();
}

Interfaces can't have static members and static methods can not be used as implementation of interface methods.接口不能有静态成员,静态方法不能用作接口方法的实现。

What you can do is use an explicit interface implementation:您可以做的是使用显式接口实现:

public interface IMyInterface
{
    void MyMethod();
}

public class MyClass : IMyInterface
{
    static void MyMethod()
    {
    }

    void IMyInterface.MyMethod()
    {
        MyClass.MyMethod();
    }
}

Alternatively, you could simply use non-static methods, even if they do not access any instance specific members.或者,您可以简单地使用非静态方法,即使它们不访问任何特定于实例的成员。

You can't define static members on an interface in C#.您不能在 C# 中的接口上定义静态成员。 An interface is a contract for instances .接口是实例的契约。

I would recommend creating the interface as you are currently, but without the static keyword.我建议您按照当前的方式创建界面,但不要使用 static 关键字。 Then create a class StaticIInterface that implements the interface and calls the static C++ methods.然后创建一个实现接口并调用静态 C++ 方法的类StaticIInterface To do unit testing, create another class FakeIInterface , that also implements the interface, but does what you need to handle your unit tests.要进行单元测试,请创建另一个类FakeIInterface ,该类也实现了接口,但会执行处理单元测试所需的操作。

Once you have these 2 classes defined, you can create the one you need for your environment, and pass it to MyClass 's constructor.一旦定义了这 2 个类,就可以创建环境所需的类,并将其传递给MyClass的构造函数。

You can define static methods in c# 8 but you must declare a default body for it.可以在 c# 8 中定义静态方法,但必须为其声明默认主体。

    public interface IMyInterface
    {
          static string GetHello() =>  "Default Hello from interface" ;
          static void WriteWorld() => Console.WriteLine("Writing World from interface");
    }

or if you don't want to have any default body simply throw an exception:或者如果您不想拥有任何默认主体,只需抛出异常:

    public interface IMyInterface
    {
          static string GetHello() =>  throw new NotImplementedException() ;
          static void WriteWorld() => throw new NotImplementedException();
    }

Static members are perfectly legal in the CLR, just not C#.静态成员在 CLR 中是完全合法的,只是在 C# 中不合法。

You could implement some glue in IL to link up the implementation details.您可以在 IL 中实现一些胶水来链接实现细节。

Not sure if the C# compiler would allow calling them though?不确定 C# 编译器是否允许调用它们?

See: 8.9.4 Interface type definition ECMA-335.参见:8.9.4 接口类型定义 ECMA-335。

Interface types are necessarily incomplete since they say nothing about the representation of the values of the interface type.接口类型必然是不完整的,因为它们没有说明接口类型的值的表示。 For this reason, an interface type definition shall not provide field definitions for values of the interface type (ie, instance fields), although it can declare static fields (see §8.4.3).为此,接口类型定义不应为接口类型的值(即实例字段)提供字段定义,尽管它可以声明静态字段(见第 8.4.3 节)。

Similarly, an interface type definition shall not provide implementations for any methods on the values of its type.同样,接口类型定义不应为其类型的值提供任何方法的实现。 However, an interface type definition can—and usually does—define method contracts (method name and method signature) that shall be implemented by supporting types.然而,接口类型定义可以——而且通常确实——定义应由支持类型实现的方法契约(方法名称和方法签名)。 An interface type definition can define and implement static methods (see §8.4.3) since static methods are associated with the interface type itself rather than with any value of the type.接口类型定义可以定义和实现静态方法(参见第 8.4.3 节),因为静态方法与接口类型本身相关联,而不是与该类型的任何值相关联。

C# 8 Allows Static Members on Interfaces C# 8 允许接口上的静态成员

Beginning with C# 8.0, an interface may define a default implementation for members.从 C# 8.0 开始,接口可以为成员定义默认实现。 It may also define static members in order to provide a single implementation for common functionality.它还可以定义静态成员,以便为通用功能提供单一实现。

interface (C# Reference) 接口(C# 参考)

Eg例如

public interface IGetSomething
{
    public static string Something = "something";
}

var something = IGetSomething.Something;

They are considering adding some of those features in a future version of C# called C# "Ten".他们正在考虑在未来的 C# 版本中添加其中一些特性,称为 C#“十”。 These theoretical features might allow static members on interfaces, alongside with roles.这些理论特性可能允许接口上的静态成员以及角色。 It would be huge step forward, it would allow generic operator overloading too, without any use of reflection.这将是向前迈出的一大步,它也将允许泛型运算符重载,而无需使用任何反射。 Here is an example snippet how it is planned to work, using the classic monoid example, which is just jargon for saying "something that can be added".这是一个示例片段,它是如何计划工作的,使用经典的 monoid 示例,这只是说“可以添加的东西”的行话。 Taken directly from Mads Torgersen: C# into the Future :直接取自Mads Torgersen:C# into the Future

interface IMonoid<T>
{
    static T Zero { get; }
    static T operator +(T t1, T t2);
}

public static T AddAll<T>(T[] ts) where T : IMonoid<T>
{
    T result = T.Zero;
    foreach (T t in ts) { result += t; }
    return result;
}

role IntAddMonoid extends int : IMonoid<int>
{
    public static int Zero => 0;
}

IntAddMonoid[] values = new int[] {1, 2, 4, 8, 16, 32};
int sixtyThree = AddAll<IntAddMonoid>(values); // == 63

Additional resources:其他资源:

Jeremy Bytes: C# 8 interface static members Jeremy Bytes:C# 8 接口静态成员

EDIT编辑

This post originally stated interface static members will be added in C# 8.0 , which is not true, I misinterpreted Mads Torgersen's words in the video.这篇文章原先声明接口静态成员会在C#8.0中加入,这不是真的,我误解了视频中Mads Torgersen的话。 The official C# 8.0 guide does not talk about static interface members yet, but it is clear they have been working on it for quite long now. 官方的 C# 8.0 指南还没有讨论静态接口成员,但很明显他们已经研究了很长时间。

This post is old but there are changes in C# since the last relevant post.这篇文章很旧,但自上一篇相关文章以来 C# 发生了变化。

Pre C#8预 C#8

Static methods are not a thing Static 方法不是一回事

Pre C#10/11预 C#10/11

Static methods/properties can be defined but must be implemented: Static 方法/属性可以定义但必须实现:

public interface MyInterfaceWithStaticMethod 
{
    public static String HelloWorld() => "Hello world";
}

C#10/11 C#10/11

At the time of writing it is known that the feature of static interface will come to C# but the version is unclear to me.在撰写本文时,已知 static 接口的功能将出现在 C# 中,但我不清楚版本。

According to this article you can now try out 'static abstract members in interfaces' with a preview of C#10 .NET6根据这篇文章,您现在可以通过 C#10 .NET6 的预览试用“接口中的静态抽象成员”

On the other hand according to this article it will only be released in C#11.另一方面,根据这篇文章,它只会在 C#11 中发布。

您可以通过反射调用它:

MyInterface.GetType().InvokeMember("StaticMethod", BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod, null, null, null);

As to why you cannot have a static method on an interface: Why Doesn't C# Allow Static Methods to Implement an Interface?至于为什么不能在接口上使用静态方法: 为什么 C# 不允许静态方法实现接口?

However, I would suggest removing the static methods in favor of instance methods.但是,我建议删除静态方法以支持实例方法。 If that is not possible, then you could wrap the static method calls inside of an instance method, and then you can create an interface for that and run your unit tests from that.如果这是不可能的,那么您可以将静态方法调用包装在一个实例方法中,然后您可以为此创建一个接口并从中运行单元测试。

ie IE

public static class MyStaticClass
{
    public static void MyStaticMethod()
    {...}
}

public interface IStaticWrapper
{
    void MyMethod();
}

public class MyClass : IStaticWrapper
{
    public void MyMethod()
    {
        MyStaticClass.MyStaticMethod();
    }
}

I see no issues other than the compiler thinking that I should not do this.除了编译器认为我不应该这样做之外,我没有看到其他问题。 C# can't inherit from more than one base class, real bummer when you are used to be able to do this, frontally you can do several interfaces, so I abuse that to sneak in the features I need ;-) C# 不能从多个基类继承,当你习惯这样做时真的很糟糕,正面你可以做几个接口,所以我滥用它来潜入我需要的功能;-)

You should check for null etc however here is a simplified version that implements Parse to get a class from a web service or database您应该检查 null 等,但是这里是一个简化版本,它实现了 Parse 从 Web 服务或数据库中获取类

/// <summary>
/// Implements parse
/// </summary>
/// <typeparam name="T">the type to parse</typeparam>
public interface IParse<T>
{ 
    /// <summary>
    /// implements parse from string to type
    /// </summary>
    /// <param name="text">value to parse</param>
    /// <returns></returns>
    static T Parse(string text)=>JsonConvert.DeserializeObject<T>(text, settings:new JsonSerializerSettings() { ConstructorHandling= ConstructorHandling.AllowNonPublicDefaultConstructor });

    /// <summary>
    /// implements parse from string to type
    /// </summary>
    /// <param name="text">value to parse</param>
    /// <param name="settings">the settings to us</param>
    /// <returns></returns>
    static T Parse(string text, JsonSerializerSettings settings) =>JsonConvert.DeserializeObject<T>(text, settings);
}

Then I just call the interface in code that has List as the return value.然后我只是在以 List 作为返回值的代码中调用接口。

Here is a snip where I read JSON from the database as populating it to a type that has Json implemented这是我从数据库中读取 JSON 并将其填充到已实现 Json 的类型的片段

//some plugging code

using (var reader = cmd.ExecuteReader(behavior: CommandBehavior.CloseConnection | CommandBehavior.SingleResult))
{
    if (reader.HasRows)
    {
        while (reader.Read())
        {
            rows++;
            try
            {
                var json = reader.GetString(0);

                result.Add(IParse<T>.Parse(json));
            }
            catch
            {
                failed++;
            }
        }
    }
}
//other plugging code

With >ver version 8 you have the default implementation so "pandora's box is open"使用 >ver version 8,你有默认的实现,所以“潘多拉的盒子是打开的”

You can use simply:您可以简单地使用:

     public interface MyInterface<T>
     {
         T Method();
     }
     
     public class MyClass<T> : MyInterface<T>
     {
         public T Method() => //Your implementation   
     }

So you use:所以你使用:

    var result = new MyClass<T>().Method();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM