静态接口等效 C#

Static interface equivalent C#

我过去曾使用过单例,我知道这是对一些试图解决静态接口问题的人的解决方案。在我的例子中,我不能真正使用单例,因为我有一个外部 class 是我继承的,我无法控制这个(库)。

基本上,我有许多 classes 继承自 "TableRow"(库中的 class),我需要这些 classes 中的每一个来实现一个某些静态方法(例如:GetStaticIdentifier)。最终,我需要将这些对象存储在它们的一种基本类型中,并对这个特定类型使用静态方法。

我的问题是,除了使用单例之外,还有其他解决方案吗? C# 中是否有我不知道的功能可以帮助我解决这个问题?

您似乎想提供一些元信息以及 TableRow 的子class;无需实例化特定子class.

即可检索的元信息

虽然 .NET 缺少静态接口和静态多态性,但这可以(在某种程度上,见下文)用 custom attributes 解决。换句话说,您可以定义一个自定义属性 class 来存储您想要与您的类型相关联的信息:

[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
public class StaticIdentifierAttribute : Attribute
{
    public StaticIdentifierAttribute(int id)
    {
        this.staticIdentifier = id;
    }

    private readonly int staticIdentifier;

    public int StaticIdentifier {
        get {
            return staticIdentifier;
        }
    }
}

然后您可以将此自定义属性应用于您的 TableRow subclasses:

[StaticIdentifier(42)]
public class MyTableRow : TableRow
{
    // ...
}

然后您可以检索 Type instance for MyTableRow (or any other subclass of TableRow) and use the GetCustomAttributes method 以检索 StaticIdentifierAttribute instance and read out the value stored in itsStaticIdentifier` 属性 class。

与静态接口和静态多态性相比,缺点 是编译时无法确保每个 TableRow subclass 实际上具有该属性;您将必须在运行时捕获它(并抛出异常,或忽略相应的 TableRow subclass)。

此外,您无法确保该属性 应用于 TableRow 子 class,但是,虽然这可能有点不整洁,这并不重要(如果它应用于另一个 class,它不会在那里产生任何影响,因为没有代码为其他 classes 处理过它)。

如果你绞尽脑汁,你可以获得少量的编译器检查。但是,为您想要的每个标识符实例声明一个新的结构类型无疑是疯狂的。

public interface IIdentifier
{
    int Id { get; }
}

public class BaseClass { }

public class ClassWithId<T> : BaseClass where T :  IIdentifier, new()
{
    public static int Id { get { return (new T()).Id; } }
}

public struct StaticId1 : IIdentifier
{
    public int Id { get { return 1; } }
}

public struct StaticId2 : IIdentifier
{
    public int Id { get { return 2; } }
}

//Testing
Console.WriteLine(ClassWithId<StaticId1>.Id);   //outputs 1
Console.WriteLine(ClassWithId<StaticId2>.Id);   //outputs 2

将静态 class 与通用(或非通用)扩展方法一起使用怎么样?

public static class Helper
{
  fields...

  public static void DoSomething<T>(this T obj)
  {
     do something...
  }
}