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

时间:2009-08-07 09:54:10

标签: c# generics inheritance interface static

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

interface I
{
     static  string GetClassName();
}

public class Helper
{

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

8 个答案:

答案 0 :(得分:24)

尝试使用扩展方法:

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实现的实例。

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

答案 1 :(得分:7)

您无法继承静态方法。您的代码不会以任何方式编译,因为接口因此而无法使用静态方法。

引自littleguru

  

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

     

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

     

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

答案 2 :(得分:3)

我之前尝试过在接口上设置一个静态方法,不知道为什么现在。我对此进行了书签,所以也许有帮助:

Interface with a static method by using extension methods

答案 3 :(得分:3)

如果你刚刚在类型名称之后,你可以这样做:

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

答案 4 :(得分:2)

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

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

答案 5 :(得分: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接口的类(示例),所以当我们调用我们的静态助手类传递一个Example实例时,它会对它运行静态方法。遗憾的是,将方法本身直接引用类型T作为变量是无效的,您必须将实例传递给应用程序。

答案 6 :(得分:0)

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

答案 7 :(得分:0)

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

虽然interface仅可以声明 instance 成员,但是您可以对C#的泛型使用一些简单的技巧,而无需进行反思,即可完成所追求的目标(并且无需采取任何措施)到Java风格的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 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();
    }
}

因此,AGenericMethodThatDoesntHaveAnInstanceOfT<Foo>的呼叫站点实际上如下所示:

AGenericMethodThatDoesntHaveAnInstanceOfT<Foo.Static>();