Как связать константы с интерфейсом в С#?
Некоторые языки позволяют связывать константу с интерфейсом:
Интерфейсы абстрактных 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;
};
Я хочу определить этот интерфейс таким образом, чтобы его можно было вызвать из С#.
По-видимому, С# не может определить константу, связанную с интерфейсом.
- Каков обычный способ перевода такого интерфейса на С#?
- Существуют ли какие-либо "канонические" привязки С# для интерфейсов DOM?
- Хотя С# не может, есть ли другой язык .NET, который может определять константы, связанные с интерфейсом?
Ответы
Ответ 1
Чтобы ответить на третий вопрос:
Хотя С# не может, есть ли другой язык .NET, который может определять константы, связанные с интерфейсом?
С++/CLI позволяет определять значения literal
в интерфейсе, которые эквивалентны значениям 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;
}
Затем вы можете получить доступ к значениям через С#:
public static void Main()
{
short primitiveValue = ICSSValue.CSS_PRIMITIVE_VALUE;
Debug.Assert(primitiveValue == 1);
}
Подробнее см. эту страницу в MSDN.
Отказ от ответственности:
Конструктивное решение запретить постоянные значения в интерфейсах было хорошим. Интерфейс, который раскрывает детали реализации, скорее всего, является негерметичной абстракцией. В этом примере CSS Value Type, вероятно, лучше будет перечислением.
Ответ 2
Если вам нужно место для хранения ваших констант, я бы использовал статический класс:
public static class MyConstants
{
public const int first = 1;
public const int second = 2;
public const string projectName = "Hello World";
}
Это (по крайней мере один) общий стандарт.
Ответ 3
С# не допускает константы в интерфейсах, поскольку константа - это грань реализации, которая теоретически не принадлежит типу, который определяет только протокол поведения.
Я подозреваю, что люди Java разрешают константные поля в интерфейсах либо потому, что интерфейс обрабатывается внутренне как какой-то абстрактный класс, либо потому, что им нужно, чтобы компенсировать некоторый недостаток в системе типов, например перечисления.
Я не уверен, что вы подразумеваете под "каноническими привязками для интерфейсов DOM". С# не запускается в браузере.
Тем не менее, вам нужно будет поместить ваши константы в другое место, например, в структуру или перечисление (если они являются числовыми). Возможно, после какого-то соглашения об именах поможет - если ваш интерфейс IFooBar
, то, возможно, структура, содержащая вашу константу, может быть вызвана IFooSetttings
или IFooValues
или что-то подходящее.
Я не знаю никаких языков CLR, кроме С# и VB.NET, но я уверен, что VB этого не допускает (хотя это было время).
Ответ 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
}
Ответ 5
Я добавил свойство Get only и добавил в определение значение const.
public interface IFoo
{
string ConstValue { get; }
}
public class Foo : IFoo
{
public string ConstValue => _constValue;
private string _constValue = "My constant";
}
Ответ 6
Абстрактный класс сделает все, что сделает интерфейс (ну, кроме теста a typeof(T).IsInterface
) и разрешите константы.
Возражение к константам (или перечислениям), встроенным в интерфейсы, неуместно. Это проблема именования. Константы именования в очень точном контексте, где они имеют смысл, лучше, чем называть их вне контекста.
Ответ 7
Попробуйте определить параметры мыслиемого метода и/или возвращенные значения
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
Пользовательский атрибут может быть использован:
[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);