如何将常量与C#中的接口相关联?

时间:2012-10-05 18:53:28

标签: c# c++-cli idl webidl

某些语言允许您将常量与接口相关联:

W3C抽象接口也是如此,例如:

// Introduced in DOM Level 2:
interface CSSValue {

  // UnitTypes
  const unsigned short      CSS_INHERIT                    = 0;
  const unsigned short      CSS_PRIMITIVE_VALUE            = 1;
  const unsigned short      CSS_VALUE_LIST                 = 2;
  const unsigned short      CSS_CUSTOM                     = 3;

  attribute DOMString       cssText;
  attribute unsigned short  cssValueType;
};

我想定义这个接口,以便可以从C#中调用它。

显然C#无法定义与接口关联的常量。

  • 将此类界面翻译为C#的常用方法是什么?
  • DOM接口是否有'规范'的C#绑定?
  • 虽然C#不能,但还有另一种.NET语言可以定义与接口相关的常量吗?

10 个答案:

答案 0 :(得分:16)

回答你的第三个问题:

  

虽然C#不能,但还有另一种.NET语言可以定义与接口相关的常量吗?

C ++ / CLI允许您在接口中定义literal值,这相当于C#中的static const值。

public interface class ICSSValue
{
public:
    literal short CSS_INHERIT = 0;
    literal short CSS_PRIMITIVE_VALUE = 1;
    literal short CSS_VALUE_LIST = 2;
    literal short CSS_CSS_CUSTOM = 3;

    property DOMString^ cssText;
    property ushort cssValueType;
}

然后,您可以通过C#:

访问这些值
public static void Main()
{
    short primitiveValue = ICSSValue.CSS_PRIMITIVE_VALUE;

    Debug.Assert(primitiveValue == 1);
}

有关详细信息,请参阅this page on MSDN

声明: 禁止在接口中使用常量值的设计决策很好。暴露实现细节的接口很可能是漏洞抽象。在这个例子中,CSS Value Type可能更适合作为枚举。

答案 1 :(得分:13)

如果你想要一个存放常量的地方,我会使用静态类:

public static class MyConstants
{
    public const int first = 1;
    public const int second = 2;
    public const string projectName = "Hello World";
}

这是(至少一个)共同标准。

答案 2 :(得分:7)

C#不允许接口中的常量,因为常量是一个实现方面,理论上它不属于只定义行为协议的类型。

我怀疑Java人员允许接口中的const字段,因为接口在内部被视为某种抽象类,或者因为他们需要它来弥补类型系统中的某些缺陷,如枚举。

我不确定“DOM接口的规范绑定”是什么意思。 C#无法在浏览器中运行。

那就是说,你需要将常量放在其他地方,比如结构或枚举(如果它们是数字的)。也许遵循某种命名约定会有所帮助 - 如果你的接口是IFooBar,那么包含你的常量的结构可能被称为IFooSetttingsIFooValues或任何合适的结构。

我不知道除C#和VB.NET之外的任何CLR语言,但我很确定VB不允许这样做(尽管已经有一段时间了)。

答案 3 :(得分:4)

我一直都在使用SO,但这是我在这里发表的第一篇文章。我发现这篇文章,试图解决同样的问题。当我看到使用静态类的帖子(由Servy)时,它让我考虑通过将接口嵌入到静态类中来解决这个问题。

// define an interface with static content
public static class X {
    // define the interface to implement
    public interface Interface {
        string GetX();
    }

    // static content available to all implementers of this interface
    public static string StandardFormat(object x) {
        return string.Format("Object = {0}", x.ToString());
    }
}

// Implement the interface
public class MyX : X.Interface {
    public override string ToString() {
        return "MyX";
    }

    #region X.Interface Members

    public string GetX() {
        // use common code defined in the "interface"
        return X.StandardFormat(this);
    }

    #endregion
}

答案 4 :(得分:4)

我添加了一个Get only属性,并在定义中使用const进行备份。

public interface IFoo
{
    string ConstValue { get; }
}

public class Foo : IFoo
{
    public string ConstValue => _constValue;
    private string _constValue = "My constant";
}

答案 5 :(得分:2)

C# 8 现在允许在 interface 定义中使用常量。

答案 6 :(得分:1)

抽象类将执行接口将执行的所有操作(除了传递typeof(T).IsInterface测试之外)并允许常量。

对接口中嵌入的常量(或枚举)的异议是错误的。这是一个命名问题。在具有意义的非常精确的上下文中命名常量比在上下文中命名它们更好。

答案 7 :(得分:0)

尝试将其定义为方法参数和/或返回值

public enum IFIleValue
{
    F_OK = 0,
    F_WRONG_NAME = -1,
    F_ERROR_OBJECT_DATA = -2,
};

public interface IFile
{
     IFIleValue New(String Name=null);
     IFIleValue Open(String Path);
     IFIleValue Save();
     IFIleValue SaveAs(String Path);
     IFIleValue Close();
}

答案 8 :(得分:0)

可以使用自定义属性:

[Constant("CSS_INHERIT", 0)]
[Constant("CSS_PRIMITIVE_VALUE", 1)]
public interface BlaBla

自定义属性类如下:

[AttributeUsage(AttributeTargets.Interface, AllowMultiple = true, Inherited = false)]
public class ConstantAttribute: Attribute
{
    public ConstantAttribute(string key, object value)
    {
        // ...
    }
}

可以使用

检索常量
object[] attributes = typeof(BlaBla).GetCustomAttributes(typeof(ConstantAttribute),
    inherit: false);

答案 9 :(得分:0)

有同样的问题-需要在接口中定义常量。 发现了另一种可能性:通过在接口上使用扩展方法。 像这样:

public interface IFoo
{
    // declarations
}
 
public static class IFooExtensions
{
    public static int Bar(this IFoo x) => 50;
}

但是,这将需要接口实例从中获取常量:

IFoo foo;
foo.Bar();

您还可以在接口实现中使用此常量:

public class Foo: IFoo
{
    public Foo() {
        var x = this.Bar();
    }
}