Вы не можете объявить объявление вложенного класса, интерфейса, структуры или перечисления внутри интерфейса или перечисления.
Вложенные объявления интерфейсов, перечислений, структур и классов допускаются только внутри структуры или класса.
Объявите класс в том же пространстве имен.
[Serializable]
public class StackEmptyException :
InvalidOperationException
{
public StackEmptyException() :
base("Cannot pop an item from an empty stack")
{
}
public StackEmptyException(string message) :
base(message)
{
}
/// <summary>Used for serialization. Never forget it!</summary>
protected StackEmptyException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) :
base(info, context)
{
}
}
В C # хорошее соглашение называть каждый класс исключений XXXException.
Поскольку извлечение элемента из пустого стека является недопустимой операцией, я бы использовал InvalidOperationException в качестве базового типа исключения.
Существует также несколько базовых типов, которые вы можете использовать, например, ArgumentException, ArgumentNullException, InvalidOperationException, ApplicationException.
Вместо того, чтобы использовать простое исключение, я бы предложил вам использовать хотя бы ApplicationException, чтобы люди могли лучше фильтровать ваши исключения в catch.
Желательно, чтобы вы использовали тип исключения, уже объявленный во фреймворке, если вы можете, их много, и обычно их достаточно, для вашего примера я бы использовал InvalidOperationException напрямую без написания нового исключения.
Я также предлагаю вам сделать его сериализуемым (добавить атрибут [Serializable] и конструктор сериализации копирования), или в будущем люди будут обвинять вас в том, «почему этот парень не сделал свое исключение сериализуемым, почему!».
Одно большое различие между java и C # в отношении исключения состоит в том, что в C # каждый метод может генерировать исключение, например C ++. Вам не нужно (и вы не можете) указать, какие исключения может вызвать метод.
Однако вы можете добавить комментарий ...
/// <summary>Pop an item from the stack.</summary>
/// <returns>The element removed from the stack.</returns>
/// <exception cref="System.InvalidOperationException">Throws InvalidOperationException if stack is empty.</exception>
public object Pop() { ... }
Чтобы заставить ваш код вызывать только ваше исключение, нужно объявить главный конструктор как внутренний.
В C # внутренние члены видны только в сборке, где они объявлены.
Поэтому, если вы пишете библиотеку, вы можете просто добавить внутреннее ключевое слово.
Вы не можете запечатать класс, если хотите сохранить его сериализацию, но никто не сможет вызвать ваш конструктор за пределами вашей библиотеки.
[Serializable]
public class StackEmptyException :
InvalidOperationException
{
// This constructor is internal, it means, only the assembly that contains this exception can throw it.
// In C# there is not the "friend" keyword like in C++ so we can just use internal.
internal StackEmptyException() :
base("Cannot pop an item from an empty stack")
{
}
/// <summary>Used for serialization. Never forget it!</summary>
protected StackEmptyException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) :
base(info, context)
{
}
}
Однако нет способа объявить «защищенную» вещь внутри интерфейса, поэтому на ваш вопрос не может быть положительного ответа.
Также методы, события и свойства в интерфейсах являются общедоступными.
Вы можете использовать абстрактный класс для этого, но, конечно, в C # (например, Java) у вас нет множественного наследования, поэтому, возможно, он вам не нужен.
Однако исключения должны быть общедоступными, иначе никто не сможет поймать ваше исключение за пределами вашего класса, и это плохой дизайн!
Возможно, вы пытаетесь заставить язык выполнить что-то не очень хорошее с точки зрения дизайна.
Исключения должны быть публичными.
Исключения в .NET не являются частью контракта интерфейса, только метод свойств и события являются частью контракта интерфейса.