Generic Methods as Casts


Somebody just asked me which of the following API design alternatives is better. They both do what we could call “casting.”


 


// Generic Method “Cast”


var foo = someInstance.SomeMethod<IFoo>();


 


// Simple Cast


var foo = (IFoo)someInstance.SomeMethod();


The Generic method approach can potentially have two benefits. A constraint can tell users what the subset of valid casts is. For example, the following API will allow casts to a collection (a subtype of IEnumerable):


 


public TCollection SomeMethod<TCollection>() where TCollection:IEnumerable {


   


}   


If the user calls this method and tries to “cast” the return value to let’s say an Int32, the compiler with complain. For example,


 


var int someInstance.SomeMethod<int>();


… will generate the following error:


 


The type ‘int’ must be convertible to ‘System.Collections.IEnumerable’ in order to use it as parameter ‘TCollection’ in the generic type or method ‘SomeClass.SomeMethod<TCollection>()’


Secondly, the Generic method might do different things based on the type parameter. The method relying on a simple cast has now knowledge about the type the user will cast it’s return value to.


 


public TCollection SomeMethod< TCollection >()


    where TCollection:IEnumerable,new() {


   


    TCollection newCollection = new TCollection ();


    ArrayList newArray = newCollection as ArrayList;


    if (newArray != null) newArray.Capacity = 0;


    return newCollection;


}  


If neither of these benefits applies in your case, I would use a simple cast. It’s more transparent in terms of what’s going on. The users of a generic method might wonder what kind of “magic” is being done with the generic type parameter.

Comments (3)

  1. Tom Kirby-Green says:

    Hi Krzysztof,

    Do you and Brad plan to write an updated edition of the Framework Class Guidelines? I was wondering if you chaps planned covering designing types for more declarative APIs (i.e. XAML bindings), designing types to enable rich and efficient LINQ to Object queries and maybe designing types to support a more functional style of programming.

    Or maybe none of these but something different. Do you envisage a new edition of the book any time?

    Kind regards,

    tom

  2. Another nice feature of doing it with a generic is that sometimes the type can be inferred.  My personal favorite example is:

    public object GetValue(string key, object defaultValue)

    {

      if (this.Values.Contains(key))

        return this.Values[key];

      else

        return defaultValue;

    }

    // call like this…

    int x = (int)configuration.GetValue("X", 0);

    Can turn into:

    public T GetValue<T>(string key, T defaultValue)

    {

      if (this.Values.Contains(key))

        return (T)this.Values[key];

      else

        return defaultValue;

    }

    // call like this…

    int x = configuration.GetValue<int>("X", 0);

    // or even cooler, like this…

    double z = configuration.GetValue("Z", 0.0);

    That’s the cool bit…

  3. Tom, we are thinking about updating the guidelines with C# 3.0 and Framework 2.0+ things. We just don’t yet have concrete plans. I am starting to draft guidelines (as we speak) and I will post them to the blog. At some point, I will try to fold them into the book.