I have an implementation of this answer† in some code of mine, as:
private interface IMath<T> {
internal T Add (T value1, T value2);
internal T Negate (T value);
}
private class Math<T> : IMath<T> {
internal static readonly IMath<T> P = Math.P as IMath<T> ?? new Math<T>();
// !!! My question concerns this portion of code:
T IMath<T>.Add (T a, T b) { NoSupport(); }
T IMath<T>.Negate (T a) { NoSupport(); }
private static void NoSupport () =>
throw new NotSupportedException($"no math ops for {typeof(T).Name}");
// !!! End code-of-interest.
}
private class Math : IMath<int>, IMath<float> {
internal static Math P = new Math();
int IMath<int>.Add (int a, int b) { return a + b; }
int IMath<int>.Negate (int value) { return -value; }
float IMath<float>.Add (float a, float b) { return a + b; }
float IMath<float>.Negate (float value) { return -value; }
}
Where the intent is e.g.:
static T Negate <T> (T v) => Math<T>.P.Negate(v);
// elsewhere...
_ = Negate(3); // ok (int)
_ = Negate(3.0f); // ok (float)
_ = Negate(3.0); // throws NotSupportedException (double)
That NoSupport()
function is what I am having a problem with. I just added it to take care of throwing an exception and a message for unsupported types, to try to keep the code simple as I add more operations.
However, it fails to compile (C# 8) with the expected "not all control paths return a value" error in the two methods (Add
and Negate
) that call it.
I understand that, and I understand why it's not compiling, and that makes sense. But, then, how can I accomplish my goal of keeping the code simple and convenient here while also satisfying the compiler?
From the research I've done so far, it appears there isn't a way to specify that a method specifically doesn't return, but I'm wondering if there's maybe a way to ...
- ... specify that
NoSupport()
always throws an exception? Or ... - ... mark a line of code as unreachable (e.g. after the call to
NoSupport()
)? Or ... - ... mark a method as always actually returning a value (overriding the compiler's analysis)?
My primary goal is to eliminate redundant code (i.e. I'm open to other approaches), my secondary goal is to learn about C#'s specific options for dealing with methods where all paths do return a value even if the compiler can't see it (are there any options?).
I have this feeling that there is a very straightforward approach and that I just can't see the forest for the trees right now.