15

In my current project I have come across the requirement to create generic classes with the same name, but different numbers of generic parameters. For example:

MyClass<T1>
MyClass<T1, T2>
MyClass<T1, T2, T3>

Given that I want all of these in the same namespace, I am confused as to how to structure and name my classes and files?

If we follow the idea that we should have classes limited to one per file and that files should be in a folder structure that represents namespace hierarchy and that the name of the file should match the name of the class, how do I deal with this situation?

What I am really asking here is what should I name the file that contains MyClass<T1>, and what should I name the file that contains MyClass<T1, T2>? I am not asking what the names of the type parameters should be.

9
  • Give us some specific examples that describe the problem in better detail. The examples you've provided are too... erm, generic. What do you mean by "how to structure and name my classes and files?" Jan 16, 2015 at 0:07
  • Microsoft does this itself by just appending a number to the type parameter. See the Tuple docs: msdn.microsoft.com/en-us/library/…
    – Pete
    Jan 16, 2015 at 0:09
  • @Pete: That really only applies to Tuple. Microsoft also uses the TKey, TValue convention. Func has a TResult type parameter. Though I do agree that you can use T1, T2, etc. for a variable number of input parameters that don't otherwise have specific uses like TKey and TValue. Jan 16, 2015 at 0:11
  • @RobertHarvey Well, yes but only in the context of an actual key/value collection such as a dictionary. For anything consisting of a variable number of types they append a number. Here's another example: msdn.microsoft.com/en-us/library/dd402872(v=vs.110).aspx
    – Pete
    Jan 16, 2015 at 0:14
  • 1
    Well, your edits obsolete some of the comments. :) Why can't you just keep the classes in the same physical file? If they're so different that you need to keep them in separate files then can you tell us what makes them different?
    – Pete
    Jan 16, 2015 at 0:31

3 Answers 3

17
MyGenericClass`1.cs
MyGenericClass`2.cs
MyGenericClass`3.cs

And so on, where the number after the backtick is the number of generic type parameters. This convention is used by Microsoft.

Alternatively, you can use something like

MyGenericCollectionClass[TKey, TValue].cs

which preserves not only the number of generic type parameters, but also their specific names. Granted, it doesn't preserve the angle brackets, but we can't have everything in life we want, can we?

6
  • 1
    The compiler internally mangles the name of generic types, adding a backtick and the number of generic parameters since .NET does not allow multiple types with the same name with a differing number of generic parameters but C# does. So the file naming convention matches what the compiler does. Jan 16, 2015 at 9:03
  • 1
    I wanted to prove you wrong, but actually you are correct: github.com/dotnet/corefx/tree/master/src/… I don't like this convention.
    – Den
    Jan 16, 2015 at 9:25
  • 2
    @Den, it seems that now they have regreted from that convention. Maybe it implied some problem? github.com/dotnet/corefx/commit/…
    – Sam
    Aug 29, 2016 at 15:49
  • @Sam Hopefully, not a communication problem between Microsoft teams. Because nobody else is doing it. Also it's up for the compiler team, not library team to decide in my opinion.
    – Den
    Aug 30, 2016 at 8:45
  • 2
    I'd not have the balls for using " ` " in a file name. Oct 2, 2017 at 10:35
4

In the case of Tuple and Action that Pete has mentioned, Microsoft themselves use a single file - see Tuple.cs and Action.cs.

I think it partly depends on whether or not the functionality for all the classes is basically the same. Personally I dislike lumping classes into a single file, but this might be an exception. In the source code where I work I added an autogenerated (using T4) NamedTuple class which acts in the same way as Tuple, but with a string name as the first argument into the constructor.

To answer your question, if you don't want to use a single file, perhaps use MyClass_1.cs for MyClass<T1>, MyClass_2.cs for MyClass<T1, T2>, etc.

Neither option is ideal though, so I'd be inclined to suggest the "Microsoft do it this way, so..." argument.

4
  • 2
    Tuple and Action are all delegates; they don't have any implementation code, so putting all of the variations in separate files would be kinda pointless anyway. Just proves that every rule has an exception. Jan 16, 2015 at 1:03
  • Yeah generally speaking putting multiple public delegates into the same file is considered ok (provided they're related).
    – Stephen
    Jan 16, 2015 at 1:04
  • 1
    @RobertHarvey, Tuple is not a delegate, but each implementation is short anyway. Jan 23, 2015 at 17:42
  • @ArturoTorresSánchez: Right, I was thinking of Func. Jan 23, 2015 at 17:45
0

Have you asked yourself, if the classes do really have the same intent? If one class is more generic than the other, then it will be a GenericClass, a MoreGenericClass and a MostGenericClass. Imagine that each type parameter of a class adds a new dimension to the class, so it may help to ask what dimension it is.

Lets take this example:

  • Container<Thing>
  • MetricContainer<Thing, Metric>
  • MetricTransportableContainer<Thing, Metric, Transport>

I'm aware, that it is not the best example, but very expressive to show three dimensions:

  • inner Dimension, what it can load
  • metric Dimension, with which metric it can be loaded, only by count of things or by square measure or by cubical capacity or by weight
  • outer Dimension, where it can be loaded.

So you can model transportation of cars:

Container<Cars>
MetricContainer<Cars, CountMetric>
MetricTransportableContainer<Cars, CountMetric, Ship>

Transportation of fluids:

Container<Fluid>
MetricContainer<Fluid, Volume>
MetricTransportableContainer<Fluid, Volume, Shelf>

Transportation of energy:

Container<Energy>
MetricContainer<Energy, ElectricPower>
MetricTransportableContainer<Energy, ElectricPower, Box>

Transportation of sugar, cereals:

Container<CrumblyMaterial>
MetricContainer<CrumblyMaterial, Weight>
MetricTransportableContainer<CrumblyMaterial, Weight, Silo>

Oh, what a surprise: a List<T> has one dimension that represents the things the list can hold; and this is a Map<T, S> with two dimensions that represent the things the map can hold and the access keys.

12
  • 1
    I don't think you understood the question. Look at the last paragraph of the question. Jan 16, 2015 at 14:12
  • 1
    @RobertHarvey Please read the question carefully: classname should be aquivalent to filename. It's interchangeably. The problem lies in wrong analysis of the class and wrong naming of the generic classes in general. To sum up my answer: "Name it what it is and not what it seems to be."
    – shylynx
    Jan 16, 2015 at 14:34
  • 1
    @RobertHarvey Read my answer: Put one class into one file!
    – shylynx
    Jan 16, 2015 at 14:58
  • 1
    I think you're missing the point. The question asks: How do I put Tuple<T1>, Tuple<T1, T2> and Tuple<T1, T2, T3> into separate CS files in a standard way, without name clashes? Jan 16, 2015 at 15:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.