-1

I've looked over a few similar questions here and browsed a few articles on the web and haven't reached a solid conclusion that makes sense on this question. Everything I've read seems to be related to throwing something like an ArgumentException or an ArgumentOutOfRangeException. However, I don't believe that these apply based on what I've read so far. If they truly do apply to my situation can you please explain (and provide documentation) as to why it is the best fit?

I have a generic class Foo<T> that has a property of type T. The type T is only valid if it is one of two types Bar and BarFoo. Therefore there is an exception thrown in the constructor if T is an invalid type:

public class Foo<T> {
    public T ID { get; private set; }
    public Foo(T id) {
        if (typeof(T) != typeof(Bar) || typeof(T) != typeof(BarFoo))
            throw new Exception("Invalid type message goes here...");

        if (id is Bar)
            ID = (Bar)(object)id;
        else if (id is BarFoo)
            ID = (BarFoo)(object)id;
    }
}

This is a simple example, but I'm not sure what exception should be thrown in this case since T is specified at the time of creating the object:

Foo<int> myFoo = new Foo<int>(3);

What exception should be thrown when the type of T is supplied at the class level instead of method level? If both are treated the same, then please provide a thorough explanation as to why this is true.

NOTE

Question has been closed, and design has since been changed. I suggest viewing the duplicate, or the answer below. No further comments are necessary.

Hazel へいぜる
  • 2,751
  • 1
  • 12
  • 44
  • You mention Bar and BarFoo, but then your actual code shows int and short. Which is it? Anyways, seems like generics aren't appropriate here if you're going to be casting it to a specific type. – mason Jun 26 '19 at 20:59
  • 2
    If your method only works with specific concrete types, then just create two overloads for those two types. It's not a generic method. How is the caller supposed to know what type to pass if `T` is not constrained to anything? – Rufus L Jun 26 '19 at 21:00
  • ive seen this throw on the static constructor. – Daniel A. White Jun 26 '19 at 21:01
  • 2
    Don't throw any exception. Don't make it possible for someone to pass the wrong type of argument. If you can use a generic constraint (there's some base type or common interface you can work with) do that. If not, make two methods. Otherwise there's no point in even using a generic argument. If the type in the constructor argument was `object` instead of `T` it would be exactly the same. Never allow a runtime error when you can have a compiler error instead. Compiler errors are better because you see them right away and when you fix them they're gone. – Scott Hannen Jun 26 '19 at 21:03
  • 1
    All the commenters and answerers are correct: **you are working against the purpose of the feature**. It's called "generics" because it is supposed to encourage you to think about code *generically*. If there are only two possible values then that is very *specific*, and you should write two specific types. But the bigger problem here is that you have an XY problem. – Eric Lippert Jun 26 '19 at 22:24
  • An XY problem is: you have a real problem, and you've come up with a bad solution to that real problem, and the bad solution doesn't work, and now you're asking a question about the bad solution, which people are answering. But the solution is bad! Rather than asking how to make your bad solution work, ask a question about the real problem that you have, and get a good solution to it. – Eric Lippert Jun 26 '19 at 22:25

1 Answers1

1

No exception type is appropriate here because the situation makes no sense.

I would reconsider your design. You claim that Foo is generic, but it can only accept one of two supposedly orthogonal types. If there is no common base type or interface between Bar and BarFoo, then how can Foo be generic?

What do you do with ID that can apply to either Bar or BarFoo (but nothing else) without reflection or a ton of switches depending on the type?

You could try creating an abstract generic type with concrete implementations:

public abstract Foo<T> {
}

public FooBar : Foo<Bar> { 
}

public FooBarFoo : Foo<BarFoo> {
}

but there's nothing stopping someone from implementing another type that uses something other than Bar or BarFoo. But at least there's not an easy way to use some other type.

D Stanley
  • 149,601
  • 11
  • 178
  • 240
  • Thanks for the feedback! I've over simplified the problem to make it a little easier to be clear with my question. Let's say for example all but two types are valid and say I don't allow types such as `byte` or `short` because they are guaranteed to overflow with any operations that could possibly be performed by the object itself. The question at hand is focused on if the type isn't going to be supported by the object, then how do I relay that information and refuse to process that type? – Hazel へいぜる Jun 26 '19 at 21:10
  • Again, you can't constrain generic arguments to multiple types. I've offered a possible alternate design that might be helpful, but constraining generics to _multiple_ types will likely be more trouble than it's worth. IMHO the exception type you throw is the least of your problems. – D Stanley Jun 26 '19 at 21:20
  • Also note that math operations are _not_ generic. There are overloads that are bound at runtime, so trying to use them with generics will be problematic. So I still don't see how you're _using_ the generic argument in a way that suggests this is a good design. – D Stanley Jun 26 '19 at 21:22