I’ve just seen a blog entry about C# generics, concerning C#’s lack of typedefs. Actually, C# has a way of aliasing classes, using the using directive:

using IntList = System.Collections.Generic.List<int>;

IntList = System.Collections.Generic.List<int>;

Quite simple. This has been there since version 1, but it wasn’t quite useful until now.

Creating empty classes as suggested in the above link is a bad idea, in my opinion. You have to maintain them, and it can be awkward for interoperating assemblies (think of two assemblies defining different “alias classes” for the same type.)

Edit: Also see this post at Eric Gunnerson’s blog.

Tagged with:
 

7 Responses to The Hidden C# "Typedef"

  1. bang says:

    It doesn’t seem to be possible to use this feature nested ?

    Or am I doing something wrong ?

    Sample :

    using IntList = System.Collections.Generic.List<int>;

    using NestedIntList = System.Collections.Generic.List<IntList>;

  2. aelij says:

    No, you can’t nest using directives. I’ve become convinced that using it for generics should be discouraged. Just write List<int>! :) It’s much clearer, and really not that much of extra code. Even List<List<int>> is just fine.

  3. krypto says:

    I’ve found that the necessity for #typedef in C# lies heavily in conjunction with the necessity for multi-file preprocessor #define’s and #if/else testing.  Using the "using MyType = InherentType;" for each file doesn’t seem to be truly necessary – aesthetics not considered – but there are some rare occasions when it would be more convenient and more CTS-friendly to be able to #define SOMETHING in file1.cs and perform a #if SOMETHING in file2.cs …

    but then the necessity for a #typedef increases.  Think about how architecture-specific value types were used in C/C++.  Consider…

    #if _X86

     using INT32 int

    #elseif _X64

     using INT32 short

    #else

     using INT32 long

    #endif

    Granted, System.Int16, System.Int32, and System.Int64 solved this particular problem, but when these #typedef’s are used like this, the data types are defined from [U]INT8 all the way up to [U]INT64 (and I’ve even seen INT128).

    It just seems to me that the necessity for a #typedef in C# is more closely related to the ability to perform preprocessor testing across multiple source files.

  4. Eduard Ralph says:

    This solution actually only works for one file at the time and only in the declared namespace. It doesn’t help you if all you really want is to define one type at one place and use it in several. I commonly run into this kind of problem when I want to define a List of something and use them in several places. The only option then is to define a class which inherits from that List, e.g.

    public class IntList : List<int>

    {

       // write constructors here

    }

  5. aelij says:

    That’s usually a bad idea, in my opinion. And writing IntList instead of List<int> just saves a couple of characters. It may come handy in cases where the type is a bit longer (e.g. Expression<Func<Func<int, string>, bool>>) – but what name would be more descriptive than the original?

    I say – stick to the full name, don’t subclass unless it actually means something and use the using directive only when you have a name collision and you don’t want to write the full namespace every time.

  6. KoD666 says:

    What about WPF? Usage of generics in XAML is very limited and there is no easy way to define DataTemplate that uses a parametrized type.

    Unfortunately `using` directive doesn’t solve this problem. Only solution I’ve found is to derive class from generic class and put parameters in base definition. But this is only partial solution because every time I must define all needed constructors and I cannot use any generic `struct`’s (deriving from value-type is forbidden).

  7. aelij says:

    Actually, there is an easy way to define a DataTemplate for a generic type, for example:

    <DataTemplate DataType="{x:Type col:List`1[System.String]}">

       <TextBlock Text="This is a List{string}" Foreground="Red" />

    </DataTemplate>

    A few notes:

    1. The TypeExtension only resolves the namespace before the colon and passes a concatenation of it and the what's after the colon to Assembly.GetType(). So you cannot use the XAML namespace mapping for the type parameter (e.g. col:List`1[sys:String]).

    2. You can always write your own type-parsing MarkupExtension for more complex scenarios.

    3. You can implement a DataTemplateSelector. In many cases the DataTemplate.DataType is quite insufficient. The simplest example – it doesn't support inheritance; the type must exactly match the runtime type of the object.

Set your Twitter account name in your settings to use the TwitterBar Section.