58

Assume I have the type

public class A<T> { }

and somewhere in the code I want to throw an exception related to incorrect usage of that type:

throw new InvalidOperationException("Cannot use A<T> like that.");

So far, so good, but I don't want to hardcode the classes name, so I thought I could maybe use

throw new InvalidOperationException($"Cannot use {nameof(A<T>)} like that.");

instead, but in this context I don't know the exact type T. So I thought maybe I could do it with template specialization like in C++:

throw new InvalidOperationException($"Cannot use {nameof(A)} like that.");

or

throw new InvalidOperationException($"Cannot use {nameof(A<>)} like that.");

but those yield

Incorrect number of type parameters.

and

Type argument is missing.


I absolutely don't want to hardcode the classes name for it might change later. How can I get the name of the class, preferably via nameof?

Optimally, what I want to achieve is "Cannot use A<T> like that." or "Cannot use A like that.".

Thomas Flinkow
  • 4,845
  • 5
  • 29
  • 65
  • 1
    Just Curious. Is there a reason you don't just add a where constraint on the type of T so that you can't call the method if T is not of some Type? – Lithium Apr 18 '18 at 11:04
  • 1
    @Lithium sure, constraints would be the way to go, but this is not about the type argument, but rather it's like a warning for the developer that they shouldn't use `A` in that particular case at all. – Thomas Flinkow Apr 18 '18 at 11:05
  • 1
    `nameof(type)` is **compiled** into the assembly, so **it** is hardcoded, but in the assembly. Runtime it can be considered a constant. – Maarten Apr 18 '18 at 11:11
  • 1
    @Maarten you're right, but when I change `A`'s name in the IDE, it will change all the ``nameof(type)` with it, which would not be a case for a "develop-time" constant. – Thomas Flinkow Apr 18 '18 at 11:12
  • 1
    @ThomasFlinkow I see, so A is being passed to some method, and that method is throwing the exception because it shouldn't be passed `A` objects? Just asking since if you want this as a warning to developers, throwing an exception only warns them when they try to run it. It seems like you could resolve this be restricting the Type of T or the types of the parameters used by methods where `A` is being erroneously passed. Anyway design questions probably off topic to the question. – Lithium Apr 18 '18 at 11:22
  • @Lithium yeah, you got that quite right. Thanks for the suggestion of overthinking the design :) – Thomas Flinkow Apr 18 '18 at 11:24

4 Answers4

47

Have you tried:

typeof(T).FullName;

or

t.GetType().FullName;

Hope it works for you.

Pacheco
  • 950
  • 11
  • 18
  • I'm afraid that won't help, because I don't care about `T`, but rather about `A` only. Thank you anyways. – Thomas Flinkow Apr 18 '18 at 11:10
  • Sorry in thi case.. will becan use.. 'This': `this.GetType().FullName`. But glad you already get an answer – Pacheco Apr 18 '18 at 11:22
  • 1
    `nameof()` evaluates to a `const String` so it can be used in other const strings and concatenated in string literals - you can't do that with `Type.FullName`, unfortunately. – Dai Jul 20 '21 at 12:16
38

If you don't care about displaying T, you can just use e.g. nameof(A<object>), assuming object complies with the generic type constraints.

This results in "Cannot use A like that."

If you want to print exactly A<T>, you could use:

$"{nameof(A<T>)}<{nameof(T)}>"

But only from within the class, as T does not exist elsewhere.

Rotem
  • 21,452
  • 6
  • 62
  • 109
  • 1
    thank you, this is sufficient and perfectly fine. I will accept this as soon as SO will let me. – Thomas Flinkow Apr 18 '18 at 11:06
  • 12
    This will give you `A` though, not `A` – DavidG Apr 18 '18 at 11:09
  • 1
    @DavidG From what I understand that is what OP is asking for: "Optimally, what I want to achieve is "Cannot use A like that."" – Rotem Apr 18 '18 at 11:10
  • Yep, @Rotem is correct. Sorry to all if that wasn't clear in the question. – Thomas Flinkow Apr 18 '18 at 11:11
  • Because almost everything is treated as an object (in an OOP language) you can do it that way. – Markus Zeller Apr 18 '18 at 11:14
  • 3
    @quetzalcoatl: `nameof` only takes what the specification calls "simple names". It then devotes more than a page to specifying exactly what's simple, but bottom line, open generics aren't simple names. What it calls "unbound generic types" are only allowed in certain contexts, and are treated specially. – Jeroen Mostert Apr 18 '18 at 11:20
  • 1
    Hmm.. interesting. Intellisense fooled me. Before I wrote it, I checked it in VS, I wrote `var foo = nameof(List<>)` and it didn't get highlighted. It got highlighted only now when I tried building it. Sorry for the confusion. It's not allowed obviously. – quetzalcoatl Apr 18 '18 at 11:25
12

Depending on the place you want to raise that exception, you can use the type.

On the instance, call this.GetType() and then get the Name or FullName property:

throw new InvalidOperationException($"Cannot use {this.GetType().Name} like that.");
Patrick Hofman
  • 153,850
  • 22
  • 249
  • 325
0

typeof(A<>).Name should work.

Patrick Fournier
  • 600
  • 6
  • 19