有没有一种简单的方法来实现它,如果可能的话,没有实例化对象:
interface I
{
static string GetClassName();
}
public class Helper
{
static void PrintClassName<T>() where T : I
{
Console.WriteLine(T.GetClassName());
}
}
答案 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)
我之前尝试过在接口上设置一个静态方法,不知道为什么现在。我对此进行了书签,所以也许有帮助:
答案 3 :(得分:3)
如果你刚刚在类型名称之后,你可以这样做:
public class Helper
{
static void PrintClassName<T>()
{
Console.WriteLine(typeof(T).Name);
}
}
答案 4 :(得分:2)
在接口定义上声明static
property
,event
或method
不被视为合法定义。这是因为接口被视为契约,因此表示将由该接口的每个客户端实例实现的内容。
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>();