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

问题描述 投票:29回答:8

有没有一种简单的方法来实现这一点,并且在可能的情况下不实例化对象:

interface I
{
     static  string GetClassName();
}

public class Helper
{

    static void PrintClassName<T>() where T : I
    {
         Console.WriteLine(T.GetClassName());
    }
}
c# generics inheritance interface static
8个回答
26
投票

尝试使用扩展方法:

public interface IMyInterface
{
     string GetClassName();
}

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

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

您不能具有用于静态方法的接口,因为这没有意义,它们是没有实例的实用方法,因此它们实际上没有类型。


7
投票

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

引自littleguru

。NET中的继承仅适用于 实例库。静态方法是 在类型级别上定义而不在 实例级别。这就是为什么压倒一切 不适用于静态 方法/属性/事件...

静态方法只保留一次 记忆。没有虚拟表等。 为他们创造的。

如果您在 .NET,您总是给它最新的 实例。 .NET隐藏了它 运行时,但是它发生了。每个实例 方法具有第一个参数的指针 (参考) 方法正在运行。这不会发生 使用静态方法(因为它们是 在类型级别定义)。 应该如何 编译器决定选择 调用方法?


3
投票

不久前,我也试图在接口上设置静态方法,现在不知道为什么。我将其添加为书签,因此可能有所帮助:

Interface with a static method by using extension methods


3
投票

如果您只是键入类型名称,则可以执行以下操作:

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

2
投票

在接口定义上声明static propertyeventmethod不视为合法定义。这是因为接口被视为合同,因此代表该接口的每个客户端实例实现的事物。

static声明从本质上说,static成员不需要物理客户端实现即可执行所需的功能,这不符合接口的一般概念:提供经过验证的合同。


1
投票

答案是合格的“不是,但实际上是”。您可以为给定接口的所有实现者提供静态扩展方法,然后可以从实现者的属性或其他方法中调用此方法。例如:

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();
        }
    }
}

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


0
投票

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


0
投票

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

虽然interface只能声明instance成员,但是您可以对C#的泛型使用一些简单的技巧,而无需进行反思,即可完成您要执行的操作(并且无需使用Java样式的[C0 ]设计模式过度使用)。

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

因此,如果我们有此界面:

struct

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

interface IStaticFunctionality
{
    void DoSomethingWithoutAnObjectInstance();
}

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

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

因此,如果我们使用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/ } 方法具有不同的类型,我们只需要为这些类型中的每一个定义static void DoSomethingWithoutAnObjectInstancestruct实现:

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(); } } 的呼叫站点实际上看起来像:

AGenericMethodThatDoesntHaveAnInstanceOfT<Foo>
© www.soinside.com 2019 - 2024. All rights reserved.