score:8
In your second example, you're trying to convert NamedValue<bool>
to NamedValue<TValue>
-- this won't work, because the conversion has to be valid for any type argument. You can't convert NamedValue<bool>
to NamedValue<int>
or NamedValue<string>
or NamedValue<AnythingElseOtherThanBool>
.
One solution is to make NamedValueSource<TValue>
abstract, as well as its GetNamedValues()
method, and then create a class BooleanNamedValueSource : NamedValueSource<bool>
class to use in your test.
In the linq case, the cast is not being done by the compiler; the cast occurs in a method that has already been compiled. All the compiler knows is that it is calling a method that takes IEnumerable<bool>
and returns IEnumerable<TValue>
. The specifics of that conversion are entirely invisible to the compiler.
score:12
UPDATE: This question was the subject of my blog on July 10th 2012; thanks for the great question!
Let's greatly simplify your complicated program.
public static class X
{
public static V Cast<V>(object o) { return (V)o; }
}
class C<T> {}
class D<U>
{
public C<U> value;
public D()
{
this.value = X.Cast<C<U>>(new C<bool>());
}
}
Now your second version, simplified:
class C<T> {}
class D<U>
{
public C<U> value;
public D()
{
this.value = (C<U>)(new C<bool>());
}
}
OK, so now let's ask some questions.
Why does the second program fail at compile time?
Because there is no conversion from C<bool>
to C<U>
for arbitrary U
. The compiler knows that the only way this could possibly succeed is is U
is always bool, and therefore this program is almost certainly wrong! The compiler assumes that U
is going to be something other than bool some of the time.
Why then does the first program succeed at compile time?
The compiler has no idea that a method named "X.Cast" should be treated like a cast operator for the purposes of error detection! As far as the compiler is concerned, the Cast
method is a method that takes an object in and returns a V
for whatever type parameter is provided for V
. When compiling the body of the ctor of D, the compiler has no idea whatsoever that some method, which probably isn't even in this program to begin with, is going to try to do a cast that is going to fail unless U
happens to be bool.
The compiler simply has no basis upon which to treat the first version as an error, even though it most certainly is a deeply wrong program. You'll have to wait until runtime to find out that your program is wrong.
Now let's make a third version of your program:
class C<T> {}
class D<U>
{
public C<U> value;
public D()
{
this.value = (C<U>)(object)(new C<bool>());
}
}
This succeeds at compile time, so let's ask:
Why does this succeed at compile time?
For the exact same reason that the first one succeeds at compile time. When you inserted the cast you effectively said that you wanted the newly constructed C<bool>
to be treated as an object, and so for the rest of the analysis of this expression, that expression is considered to be of type object, and not the more specific type C<bool>
.
So then why is it legal to cast object to
C<U>
in this case? Or for that matter, toV
in the first case?
It is legal to cast object to V
because V
could be the type of the object, a base type of the object or an interface implemented by the object, so the compiler allows the conversion because it figures there are a lot of ways it could possibly succeed.
Basically, it is legal to cast object
to anything that you could convert to object
. You cannot cast object
to a pointer type, for instance, because no pointer type can be cast to object
. But everything else is fair game.
By making the cast to object
first, you are removing information from the purview of the compiler; you are saying "ignore the fact that you know this is always C<bool>
for the purposes of error detection.
Source: stackoverflow.com
Related Articles
- Why does the C# compiler allow a cast to be performed with Linq but not with parentheses?
- Why does the Linq Cast<> helper not work with the implicit cast operator?
- Why does ToDictionary<K,V>() generate a compiler error when used with LINQ to SQL?
- Why does the C# compiler go mad on this nested LINQ query?
- Does LINQ work with IEnumerable?
- What does this C# code with an "arrow" mean and how is it called?
- How does LINQ expression syntax work with Include() for eager loading
- Why does this Linq Cast Fail when using ToList?
- Why does C# compiler create private DisplayClass when using LINQ method Any() and how can I avoid it?
- Does C# 7 allow to deconstruct tuples in linq expressions
- Why does a Linq Cast<T> operation fail when I have an implicit cast defined?
- Order by does not work with Concat() in LINQ
- Does 'And' vs 'AndAlso' matter with linq in vb.net?
- Does this LINQ code perform multiple lookups on the original data?
- Dynamically cast IEnumerable to IQueryable or dynamically call AsQueryable with LINQ Expressions
- My Enumerable class does not work with Linq statements like .where in c#
- Getting an invalid cast exception when trying to order a list of objects with linq
- Understanding how the C# compiler deals with chaining linq methods
- Does LINQ with a scalar result trigger the lazy loading
- Does the compiler concatenate LINQ where queries?
- LINQ does not start with on List<string>
- How does linq actually execute the code to retrieve data from the data source?
- LINQ Source Code Available
- How does this linq code that splits a sequence work?
- Why Linq Prepend() does not work with List<T>?
- Linq with where clause in many-to-many EF Code First object
- Does MongoDb C# driver works with LINQ and dynamic documents?
- Refactor Linq code and "LINQ to Entities does not recognize the method"
- Linq with safe cast and null verification
- Compiler error when using LINQ on IEnumerable<dynamic> but not if you cast it to IEnumerable<dynamic> first
- C# LINQ and Pattern Matching challenge
- Getting the difference List of two different List Objects in VB.NET
- Strange Output in using SkipWhile() in LINQ
- Linq select from two tables order by list
- Querying elastic search with linq using NEST
- How can I use the .Select(T, index) overload in a LINQ query?
- What is the correct way to Take() X-number of records with LINQ but find out if there are more
- LINQ WHERE clause using if statements
- How to optimize a code using DataTable and Linq?
- Select maximum version from collection with LINQ in EF
- Filter in linq with ID's in a List<int>
- How can I concatenate the array content with its index value
- Sum properties using LINQ
- c# linq generated query length over the limit. Is there any way we could up lift this limit?
- LINQ to XML - Load node then add to Xdocument - Namespace issue
- Nhibernate/Linq: NHibernate.QueryException : could not resolve property: Profile.class of: MyNamespace.MyObject
- How to retrieve data using Linq Query
- Asymptotic behavior IEnumerable.Intersect vs HashedSet.IntersectWith
- Having multiple Ids on linq-sql join query in c#
- SQL to LINQ translation