代码之家  ›  专栏  ›  技术社区  ›  Ryan

C类设计-我可以用什么来代替“静态抽象”?

  •  9
  • Ryan  · 技术社区  · 14 年前

    我想做以下的事情

    public abstract class MyAbstractClass
    {
        public static abstract int MagicId
        {
            get;
        }
    
        public static void DoSomeMagic()
        {
            // Need to get the MagicId value defined in the concrete implementation
        }
    }
    
    public class MyConcreteClass : MyAbstractClass
    {
        public static override int MagicId
        {
            get { return 123; }
        }
    }
    

    但是我不能因为你 can't have static abstract members .

    我理解为什么我不能这样做-任何设计的建议都会取得相同的结果?

    (为了清楚起见,我试图为库提供一个抽象的基类,但是具体的版本必须自己实现一些属性/方法,是的,保持它是静态的有很好的理由。)

    9 回复  |  直到 13 年前
        1
  •  4
  •   Allen E. Scharfenberg    14 年前

    单件模式可能有效吗?到描述如何在C中实现单例的msdn文章的链接:

    http://msdn.microsoft.com/en-us/library/ff650316.aspx

    在您的特定示例中,singelton实例可以用您的magicID扩展一个抽象基类。

    只是一个想法:)

        2
  •  5
  •   Jon Skeet    14 年前

    你基本上 不能 制作 DoSomeMagic() 使用当前设计。对…的呼唤 MyConcreteClass.DoSomeMagic 在源代码中,将被转换为 MyAbstractClasss.DoSomeMagic 在IL。它最初被称为 MyConcreteClass 迷路了。

    您可以考虑使用具有相同方法但虚拟的并行类层次结构,然后将原始类的每个实例与包含以前静态成员的类的实例相关联…可能每一个都只有一个实例。

        3
  •  3
  •   Dan Tao    14 年前

    我会质疑是否有“充分的理由”使抽象成员保持静态。

    如果您认为这些成员可能反映了派生类本身的某些属性,而不是给定的实例,那么这并不一定意味着这些成员应该是静态的。

    考虑一下 IList.IsFixedSize 财产。这确实是 友善的 属于 IList ,不是任何特定实例(即 T[] 将是固定的大小;它不会与一个不同 t[] 对另一个)。但它仍然应该是实例成员。为什么?因为 自从 可以实现多种类型 伊利斯特 因人而异 伊利斯特 到另一个。

    考虑一些需要 MyAbstractClass (从你的例子中)。如果这段代码设计得当,在大多数情况下,它不应该关心它实际处理的是哪个派生类。重要的是什么 抽象类 暴露。如果将一些抽象成员设置为静态的,那么访问它们的唯一方法就是这样:

    int magicId;
    if (concreteObject is MyConcreteClass) {
        magicId = MyConcreteClass.MagicId;
    } else if (concreteObject is MyOtherConcreteClass) {
        magicId = MyOtherConcreteClass.MagicId;
    }
    

    为什么这么乱?这样好多了,对吧?

    int magicId = concreteObject.MagicId;
    

    但也许你还有其他我没有想到的好理由。

        4
  •  2
  •   David Basarab    14 年前

    最好的选择是使用magicid接口,只使用setter

    public interface IMagic
    {
        int MagicId { get; }
    }
    

    根据静态意义的本质,只能有一个(是的,像高地人),你不能超越它们。

    使用接口假定客户机将实现合同。如果他们想要为每一个都有一个实例,或者返回一个静态变量的值,这取决于他们。

    保持事物静态的好理由也意味着您不需要在子类中重写它。

        5
  •  0
  •   JoshReedSchramm    14 年前

    不是这个选择的忠实粉丝,但是…

    您可以声明属性static而不是abstract、virtual,并引发NotImplementedException,该异常返回一条错误消息,说明必须在派生类中重写该方法。

    您将错误从编译时移动到运行时,尽管这有点难看。

        6
  •  0
  •   zneak    14 年前

    实现静态成员继承的语言通过元类来实现(也就是说,类也是对象,这些对象具有元类,并且静态继承通过元类存在)。您可以模糊地将其转换为工厂模式:一个类具有魔力成员,并且可以创建第二个类的对象。

    或者使用反射。但您不能在编译时确保派生类静态实现某个属性。

        7
  •  0
  •   bitbonk    14 年前

    为什么不把它变成一个非静态的成员呢?

        8
  •  0
  •   lesscode    14 年前
        9
  •  0
  •   Jordão    14 年前

    这个 provider pattern 例如,由ASP.NET成员资格提供程序使用的,可能是您要查找的内容。

    静态成员上不能有多态行为,因此您将有一个静态类,该类的成员委托给将封装多态行为的接口(或抽象类)字段。