tags:

views:

104

answers:

3

Why does the following compile?

public IList<T> Deserialize<T>(string xml)
{              
    if (typeof(T) == typeof(bool))
        return (IList<T>)DeserializeBools(xml);

    return null;
}

private static IList<bool> DeserializeBool(string xml) { ... do stuff ... }

But this doesn't

public MyClass<T> GetFromDb<T>(string id)
{
    if (typeof(T) == typeof(bool))
        return (MyClass<T>)GetBoolValue(id);  <-- compiler error here

    return null;
}

private static MyClass<bool> GetBoolValue(string id) { ... do stuff ... }
A: 

C# 4.0 allows declaration of covariance and contravariance on parameterized interface and delegate types.

Den
This isn't trying to use generic variance, and anyway generic variance doesn't apply to value type type arguments.
Jon Skeet
A: 

What happens if you replace

return (MyClass<T>)

with

return (MyClass<bool>)
Benjamin Confino
Then it will fail to convert from `MyClass<bool>` to the `MyClass<T>` required by the return type.
Jon Skeet
+8  A: 

The reason interfaces work is that any object might implement IList<T> (unless it's known to be an instance of a sealed type which doesn't implement it, I guess) - so there's always a possible reference type conversion to the interface.

In the latter case, the compiler isn't willing to do that because it doesn't really know that T is bool, despite the previous if statement, so it doesn't know what conversion to try between MyClass<T> and MyClass<bool>. The valid conversions to generic types are pretty limited, unfortunately.

You can fix it fairly easily:

return (MyClass<T>)(object) GetBoolValue(id);

It's ugly, but it should work... and at least in this case it won't be causing any boxing.

Jon Skeet
It does, thank you
Dominic Godin