This question is more aimed at good design practices rather than exceptions and stacks. My apologies for not being clear at first.
I want to play about with having my own exceptions for my classes in C#. In Java the following concept is perfectly legal so that if you have a few concrete implementations of a stack you can implement consistent error handling (or any other type of class)
public interface IStack
{
bool IsEmpty();
int Pop();
void Push(int element);
int Size { get; set; }
int Top();
public class EmptyException : Exception
{
}
public class SomeOtherClass
{
}
}
Of course, in C# I get an error saying that 'Interfaces cannot declare types'
What is the best way to ensure only concrete classes that implement my interface can access EmptyException etc?
Thanks
An interface cannot contain constants, fields, operators, instance constructors, finalizers, or types, nor can an interface contain static members of any kind. All interface members implicitly have public access.
Interface cannot contain fields because they represent a particular implementation of data. Multiple inheritance is possible with the help of Interfaces but not with classes.
By using interfaces, you can, for example, include behavior from multiple sources in a class. That capability is important in C# because the language doesn't support multiple inheritance of classes.
An interface defines a contract. Any class or struct that implements that contract must provide an implementation of the members defined in the interface. An interface may define a default implementation for members. It may also define static members in order to provide a single implementation for common functionality.
You cannot declare a nested class, interface, struct or enum declaration inside an interface or enum.
Nested interfaces, enums, struct and classes declarations are allowed only inside struct or class.
Declare a class in the same namespace.
[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)
{
}
}
In C# is a good convention to name every exception class as XXXException.
Since it is an invalid operation to pop an item from an empty stack, I would use InvalidOperationException as base exception type.
There are also several base types you can use, for example ArgumentException, ArgumentNullException, InvalidOperationException, ApplicationException. Instead of using the simple Exception I would suggest you to use at least ApplicationException, so people can filter your exceptions better in catch.
Is preferred that you use an exception type already declared in the framework if you can, there are a lot and usually they are enough, for your example I would have used directly InvalidOperationException without writing a new exception.
I also suggest you to make it serializable (add the [Serializable] attribute and copy serialization constructor) or in the future people will blame at you "why this guy didn't make his exception serializable, why!".
One big difference between java and C# about exception is that in C# every method can throw an exception, like C++. You don't have to (and you cannot) specify what exceptions a method can throw. You can however add a comment...
/// <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() { ... }
A way to make only your code to raise your exception is to declare the main constructor as internal. In C# internal members are visible only in the assembly where they are declared. So if you are writing a library you can just add the internal keyword. You cannot seal the class if you want still to keep it serializable, but no-one will be able to call your constructor outside your library.
[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)
{
}
}
There is however not a way to declare a "protected" thing inside an interface, so your question cannot have a positive answer. Also methods, events and properties in interfaces are all public.
You can use an abstract class for this, but of course, in C# (like java) you don't have multi-inheritance so maybe is not useful to you. Exceptions should be all public, however, or no-one can catch your exception outside your class, and this is a bad design!
Probably you are trying to force the language to perform something that is not really good from a design point of view.
Exceptions must be public. Exceptions, in .NET, are not part of an interface contract, only properties method and events are parte of the interface contract.
Perhaps I'm missing something in your design but, you don't need to do anything special to make sure a class "can" throw an exception. Any class can throw any exception it wants any time. The only requirement is that the exception class be visible.
Make sure the exception is in the same assembly and same namespace as your interface and you'll be fine.
public interface IStack
{
bool IsEmpty();
int Pop();
void Push(int element);
int Size { get; set; }
int Top();
}
public class Empty : Exception
{
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With