Интерфейсы не могут объявить тип проблемы C # - PullRequest
5 голосов
/ 08 ноября 2011

Этот вопрос больше нацелен на хорошие методы проектирования, а не на исключения и стеки.Мои извинения за то, что не были ясны вначале.

Я хочу поиграть с моими собственными исключениями для моих классов в C #.В Java следующая концепция совершенно законна, так что если у вас есть несколько конкретных реализаций стека, вы можете реализовать согласованную обработку ошибок (или любой другой тип класса)ошибка, в которой говорится, что «Интерфейсы не могут объявлять типы»

Каков наилучший способ обеспечить доступ к EmptyException только конкретным классам, реализующим мой интерфейс и т. д.?

Спасибо

Ответы [ 3 ]

7 голосов
/ 08 ноября 2011

Вы не можете объявить объявление вложенного класса, интерфейса, структуры или перечисления внутри интерфейса или перечисления.

Вложенные объявления интерфейсов, перечислений, структур и классов допускаются только внутри структуры или класса.

Объявите класс в том же пространстве имен.

    [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 не являются частью контракта интерфейса, только метод свойств и события являются частью контракта интерфейса.

6 голосов
/ 08 ноября 2011

Возможно, я что-то упустил в вашем дизайне, но вам не нужно делать что-то особенное, чтобы убедиться, что класс "может" выдать исключение. Любой класс может генерировать любое исключение в любое время. Единственное требование - чтобы класс исключений был видимым.

Убедитесь, что исключение находится в той же сборке и в том же пространстве имен, что и ваш интерфейс, и все будет в порядке.

public interface IStack
{   
    bool IsEmpty();
    int Pop();
    void Push(int element);
    int Size { get; set; }
    int Top();
}   


public class Empty : Exception
{
}
0 голосов
/ 08 ноября 2011

Пока класс, реализующий интерфейс, имеет исключение в области видимости, он может его выбросить.Я не могу понять, что вы пытаетесь описать здесь, вам придется помочь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...