带有泛型的 C# 接口静态方法调用

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1243921/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 14:08:45  来源:igfitidea点击:

C# interface static method call with generics

c#genericsinheritanceinterfacestatic

提问by Toto

Is there a simple way to implement this, and if possible without instanciating an object :

有没有一种简单的方法来实现这一点,如果可能的话,不实例化一个对象:

interface I
{
     static  string GetClassName();
}

public class Helper
{

    static void PrintClassName<T>() where T : I
    {
         Console.WriteLine(T.GetClassName());
    }
}

采纳答案by Keith

Try an extension method instead:

尝试使用扩展方法:

public interface IMyInterface
{
     string GetClassName();
}

public static class IMyInterfaceExtensions
{
    public static void PrintClassName<T>( this T input ) 
        where T : IMyInterface
    {
         Console.WriteLine(input.GetClassName());
    }
}

This allows you to add static extension/utility method, but you still need an instance of your IMyInterface implementation.

这允许您添加静态扩展/实用程序方法,但您仍然需要 IMyInterface 实现的实例。

You can't have interfaces for static methods because it wouldn't make sense, they're utility methods without an instance and hence they don't really have a type.

你不能有静态方法的接口,因为它没有意义,它们是没有实例的实用方法,因此它们没有真正的类型。

回答by Nick Clarke

I also tried to setup a static method on an interface a little while ago, not sure why now. I did bookmark this so maybe it helps:

不久前我还尝试在接口上设置静态方法,现在不知道为什么。我做了书签,所以也许它有帮助:

Interface with a static method by using extension methods

使用扩展方法与静态方法接口

回答by Dykam

You can not inherit static methods. Your code wouldn't compile in any way, because a interface can't have static methods because of this.

您不能继承静态方法。您的代码不会以任何方式编译,因为因此接口不能具有静态方法。

As quoted from littleguru:

引用自littleguru

Inheritance in .NET works only on instance base. Static methods are defined on the type level not on the instance level. That is why overriding doesn't work with static methods/properties/events...

Static methods are only held once in memory. There is no virtual table etc. that is created for them.

If you invoke an instance method in .NET, you always give it the current instance. This is hidden by the .NET runtime, but it happens. Each instance method has as first argument a pointer (reference) to the object that the method is run on. This doesn't happen with static methods (as they are defined on type level). How should the compiler decide to select the method to invoke?

.NET 中的继承仅适用于实例基础。静态方法是在类型级别而不是在实例级别定义的。这就是为什么覆盖不适用于静态方法/属性/事件......

静态方法只在内存中保存一次。没有为他们创建的虚拟表等。

如果在 .NET 中调用实例方法,则始终为其提供当前实例。这被 .NET 运行时隐藏,但它发生了。每个实例方法都有一个指向运行该方法的对象的指针(引用)作为第一个参数。静态方法不会发生这种情况(因为它们是在类型级别定义的)。编译器应该如何决定选择要调用的方法?

回答by Kent Boogaart

If you're just after the type name, you can just do this:

如果您只是在类型名称之后,则可以执行以下操作:

public class Helper
{
    static void PrintClassName<T>()
    {
         Console.WriteLine(typeof(T).Name);
    }
}

回答by Wolfwyrd

The answer is a qualified "not really but Sort Of". You can provide a static extension method to all implementors of a given interface and can then call this from your implementer in a property or another method. As an example:

答案是一个合格的“不是真的,而是 Sort Of”。您可以为给定接口的所有实现者提供静态扩展方法,然后可以从您的实现者在属性或其他方法中调用它。举个例子:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace InterfacesWithGenerics
{
    class Program
    {
        static void Main(string[] args)
        {
            Helper.PrintClassName<Example>(new Example());
            Console.ReadLine();
        }
    }

    public class Example : I
    {
        #region I Members

        public string ClassName
        {
            get { return this.GetClassName(); }
        }

        #endregion
    }

    public interface I
    {
        string ClassName { get; }
    }

    public class Helper
    {

        public static void PrintClassName<T>(T input) where T : I
        {           
            Console.WriteLine( input.GetClassName()) ;
        }
    }

    public static class IExtensions
    {
        public static string GetClassName(this I yourInterface)
        {
            return yourInterface.GetType().ToString();
        }
    }
}

Here we have an interface (I) which defines the property we care about and a static extension method (GetClassName) which is applied to all members of its type which does the grunt work of getting the information we want. We Have a Class (Example) which implements the I interface so when we call our static helper class passing in an instance of Example, it runs the static method against it. Unfortunately it is not valid to reference the type T directly within the method itself as a variable, you'll have to pass an instance into the application.

这里我们有一个接口(I),它定义了我们关心的属性和一个静态扩展方法(GetClassName),它应用于其类型的所有成员,它完成了获取我们想要的信息的繁重工作。我们有一个实现 I 接口的类(示例),因此当我们调用传入示例实例的静态帮助器类时,它会针对它运行静态方法。不幸的是,直接在方法本身中将类型 T 作为变量引用是无效的,您必须将一个实例传递给应用程序。

回答by Mike J

Declaring a staticproperty, eventor methodon an interface definition is not considered a legal definition. This is because interfaces are considered contracts and as such, represent something that willbe implemented by every client instance of that interface.

在接口定义上声明staticproperty,eventmethod不被视为合法定义。这是因为接口被视为契约,因此,代表将由该接口的每个客户端实例实现的内容。

A staticdeclaration essentially states that the staticmember does not require a physical client implementation in order to execute the required functionality and this falls short of the general concept of interfaces: providing a proven contract.

一个static声明实质上指出,static会员不需要为了执行所需功能的物理客户端实现,这属于短期接口的一般概念:提供一个行之有效的合同。

回答by codymanix

You could define the className as attribute on the specific class. This is the preferred ay to store metadata in .net. This way you can query the attribute for the given class and you do not need an instance.

您可以将 className 定义为特定类的属性。这是在 .net 中存储元数据的首选方式。通过这种方式,您可以查询给定类的属性,并且不需要实例。

回答by Dai

Yes, you can - sort-of - if you don't mind defining new types that proxy instance calls to static methods:

是的,您可以 - 有点 - 如果您不介意定义代理实例调用静态方法的新类型:

While an interfacecan only declare instancemembers, you can use a couple of simple tricks with C#'s generics, without needing reflection, to accomplish what you're after (and without resorting to Java-style AbstractFactoryBeanFactorydesign-pattern overuse).

虽然 aninterface只能声明实例成员,但您可以使用 C# 泛型的几个简单技巧,无需反射,即可完成您所追求的任务(并且无需AbstractFactoryBeanFactory过度使用Java 风格的设计模式)。

What we can do, is define a separate struct(i.e. a value-type) that contains instance members that call-into the static members we want.

我们可以做的是定义一个单独的struct(即值类型),其中包含调用我们想要的静态成员的实例成员。

So if we have this interface:

所以如果我们有这个接口:

interface IStaticFunctionality
{
    void DoSomethingWithoutAnObjectInstance();
}

...and we want to do something like this:

...我们想做这样的事情:

void AGenericMethodThatDoesntHaveAnInstanceOfT<T>()
{
    T.DoSomethingWithoutAnObjectInstance();
}

...then we can do this:

...然后我们可以这样做:

void AGenericMethodThatDoesntHaveAnInstanceOfT<T>()
    where T : struct, IStaticFunctionality
{
    T t = default;
    t.DoSomethingWithoutAnObjectInstance();

    // Note the above code uses `T t default;` instead of `T t = new T()`.
    // This is because the C# compiler currently replaces `new T()` with `Activator.CreateInstance<T>()` in the generated bytecode.
    // This has poor performance compared to `default(T)` or a normal non-generic constructor call, but the compiler does this because it's a workaround for a design-bug back in C# 6.0: https://devblogs.microsoft.com/premier-developer/dissecting-the-new-constraint-in-c-a-perfect-example-of-a-leaky-abstraction/ 
}

So if we have different types with the static void DoSomethingWithoutAnObjectInstancemethod, we just need to define structimplementations of IStaticFunctionalityfor each of those types:

因此,如果我们的static void DoSomethingWithoutAnObjectInstance方法有不同的类型,我们只需要为每个类型定义struct实现IStaticFunctionality

class Foo
{
    public static void DoSomethingWithoutAnObjectInstance()
    {
        Console.WriteLine("foo");
    }

    struct Static : IStaticFunctionality
    {
        void DoSomethingWithoutAnObjectInstance() => Foo.DoSomethingWithoutAnObjectInstance();
    }
}

class Bar
{
    public static void DoSomethingWithoutAnObjectInstance()
    {
        Console.WriteLine("bar");
    }

    struct Static : IStaticFunctionality
    {
        void DoSomethingWithoutAnObjectInstance() => Bar.DoSomethingWithoutAnObjectInstance();
    }
}

So then a call-site for AGenericMethodThatDoesntHaveAnInstanceOfT<Foo>would actually look like:

因此,呼叫站点AGenericMethodThatDoesntHaveAnInstanceOfT<Foo>实际上看起来像:

AGenericMethodThatDoesntHaveAnInstanceOfT<Foo.Static>();