Why will the below not compile? What's special about the interface that causes the compiler to think it can't cast from Container<T>
to T
, when T
is an interface? I don't think its a covariant issue, as I'm not downcasting, but perhaps it is. This is quite like Why C# compiler doesn't call implicit cast operator? but I don't think it's quite the same.
Product pIn =null;
Product pOut;
Container<Product> pContainer;
List<Product> pListIn = null;
List<Product> pListOut;
Container<List<Product>> pListContainer;
IList<Product> pIListIn = null;
IList<Product> pIListOut;
Container<IList<Product>> pIListContainer;
pContainer = pIn;
pOut = pContainer; // all good
pListContainer = pListIn;
pListOut = pListContainer; // all good too
pIListContainer = pIListIn; // fails , cant do implicit cast for some reason
pIListOut = pIListContainer; // and here too
class Container<T>
{
private T value;
private Container(T item) { value = item; }
public static implicit operator Container<T>(T item)
{
return new Container<T>(item);
}
public static implicit operator T(Container<T> container)
{
return container.value;
}
}
Cannot implicitly convert type 'Container<IList<Product>>' to 'IList<Product>'. An explicit conversion exists (are you missing a cast?)
Cannot implicitly convert type 'IList<Product>' to 'Container<IList<Product>>'. An explicit conversion exists (are you missing a cast?)
User defined conversions aren't allowed on interfaces at all. It would potentially be ambiguous, because the type you're trying to convert from could implement the interface itself - at which point what would the cast mean? A reference conversion like a normal cast, or an invocation of the user-defined conversion?
From section 10.3.3 of the C# 4 spec:
For a given source type S and target type T, if S or T are nullable types, let S0 and T0 refer to their underlying types, otherwise S0 and T0 are equal to S and T respectively. A class or struct is permitted to declare a conversion from a source type S to a target type T only if all of the following are true:
- S0 and T0 are different types.
- Either S0 or T0 is the class or struct type in which the operator declaration takes place.
- Neither S0 nor T0 is an interface-type.
- Excluding user-defined conversions, a conversion does not exist from S to T or from T to S.
and then later:
However, it is possible to declare operators on generic types that, for particular type arguments, specify conversions that already exist as pre-defined conversions
...
In cases where a pre-defined conversion exists between two types, any user-defined conversions between those types are ignored. Specifically:
- If a pre-defined implicit conversion (§6.1) exists from type S to type T, all user-defined conversions (implicit or explicit) from S to T are ignored.
- If a pre-defined explicit conversion (§6.2) exists from type S to type T, any user-defined explicit conversions from S to T are ignored. Furthermore:
- If T is an interface type, user-defined implicit conversions from S to T are ignored.
- Otherwise, user-defined implicit conversions from S to T are still considered.
Note the first nested bullet here.
(I can thoroughly recommend getting hold of the spec by the way. It's available online in various versions and formats , but the hardcopy annotated edition is also a goldmine of little nuggets from the team and others. I should confess a certain bias here, as I'm one of the annotators - but ignoring my stuff, all the other annotations are well worth reading!)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.