How to associate constants with an interface in C#?

51.9k views Asked by At

Some languages let you associate a constant with an interface:

The W3C abstract interfaces do the same, for example:

// 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;
};

I want to define this interface such that it can be called from C#.

Apparently C# cannot define a constant associated with an interface.

  • What is the usual way to translate such an interface to C#?
  • Are there any 'canonical' C# bindings for the DOM interfaces?
  • Although C# cannot, is there another .NET language which can define constants associated with an interface?
10

There are 10 answers

5
Glen Little On BEST ANSWER

C# 8 now allows constants in an interface definition.

0
Jay Schroeder On

I use SO all the time but this is my first ever post here. I found this post, trying to solve the same problem. When I saw the post on using a static class (by Servy) it got me thinking about solving this by embedding the Interface inside that static class.

// 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
}
2
Servy On

If you want a place to store your constants I would use a static class:

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

That is (at least one) common standard.

8
kprobst On

C# doesn't allow constants in interfaces because a constant is an implementation facet which theoretically does not belong in a type that only defines a behavior protocol.

I suspect the Java folks allow const fields in interfaces either because an interface is treated internally as some kind of abstract class, or because they needed that to make up for some deficiency in the type system, like enums.

I'm not sure what you mean by "canonical bindings for the DOM interfaces". C# does not run in a browser.

That said, you'll need to put your constants somewhere else, like a struct, or an enum (if they are numeric). Perhaps following some kind of naming convention would help -- if your interface is IFooBar then maybe the struct that contains your constant could be called IFooSetttings or IFooValues or whatever is appropriate.

I don't know any CLR languages other than C# and VB.NET, but I'm pretty sure VB doesn't allow this (although it's been a while).

2
MattDavey On

To answer your third question:

Although C# cannot, is there another .NET language which can define constants associated with an interface?

C++/CLI allows you to define literal values in an interface, which are equivalent to static const values in C#.

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;
}

You could then access the values via C#:

public static void Main()
{
    short primitiveValue = ICSSValue.CSS_PRIMITIVE_VALUE;

    Debug.Assert(primitiveValue == 1);
}

See this page on MSDN for more details.

Disclaimer: The design decision to disallow constant values in interfaces was a good one. An interface which exposes implementation details is most likely a leaky abstraction. In this example CSS Value Type is probably better off being an enumeration.

0
David Hyde On

I added a Get only property and backed it up with a const in the definition.

public interface IFoo
{
    string ConstValue { get; }
}

public class Foo : IFoo
{
    public string ConstValue => _constValue;
    private string _constValue = "My constant";
}
0
Michiel de Wolde On

A custom attribute can be used:

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

The custom attribute class could look like:

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

Constants can be retrieved using

object[] attributes = typeof(BlaBla).GetCustomAttributes(typeof(ConstantAttribute),
    inherit: false);
2
Chris F Carroll On

An abstract class will do everything an interface will do (well, apart from pass a typeof(T).IsInterface test) and allow constants.

The objection to constants (or enums) embedded in interfaces is misplaced. It's a naming issue. Naming constants in the very precise context where they have meaning is better than naming them out of context.

0
icar0 On

Try define it thought method parameters and/or returned values

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();
}
0
Quercus On

Got the same problem - need to define constants in interface. Found yet another possibility: by using extension methods on interface. Like this:

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

This, however, will require instance of interface to get constant from it:

IFoo foo;
foo.Bar();

And you can also use this constant in interface implementations:

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