Struct/class in question:
public struct HttpMethod
{
public static readonly HttpMethod Get = new HttpMethod("GET");
public static readonly HttpMethod Post = new HttpMethod("POST");
public static readonly HttpMethod Put = new HttpMethod("PUT");
public static readonly HttpMethod Patch = new HttpMethod("PATCH");
public static readonly HttpMethod Delete = new HttpMethod("DELETE");
private string _name;
public HttpMethod(string name)
{
// validation of name
_name = name.ToUpper();
}
public static implicit operator string(HttpMethod method)
{
return method._name;
}
public static implicit operator HttpMethod(string method)
{
return new HttpMethod(method);
}
public static bool IsValidHttpMethod(string method)
{
// ...
}
public override bool Equals(object obj)
{
// ...
}
public override int GetHashCode()
{
return _name.GetHashCode();
}
public override string ToString()
{
return _name;
}
}
The following code triggers the issue:
public class HttpRoute
{
public string Prefix { get; }
public HttpMethod[] Methods { get; }
public HttpRoute(string pattern, params HttpMethod[] methods)
{
if (pattern == null) throw new ArgumentNullException(nameof(pattern));
Prefix = pattern;
Methods = methods ?? new HttpMethod[0];
}
public bool CanAccept(HttpListenerRequest request)
{
return Methods.Contains(request.HttpMethod) && request.Url.AbsolutePath.StartsWith(Prefix);
}
}
The compiler error is created by changing the HttpMethod struct into a sealed class. The error is reported for return Methods.Contains(request.HttpMethod), note: request.HttpMethod in this case is a string. Which produces the following:
Error CS1929 'HttpMethod[]' does not contain a definition for 'Contains' and the best extension method overload 'Queryable.Contains<string>(IQueryable<string>, string)' requires a receiver of type 'IQueryable<string>'
My question is why? I can redesign the code to make it work, but I'm wanting to know why changing from struct to sealed class creates this weird error.
Edit: Adding a simplified set of example code (available here: https://dotnetfiddle.net/IZ9OXg). Take note that commenting out the implicit operator to string on the second class allows the code to compile:
public static void Main()
{
HttpMethod1[] Methods1 = new HttpMethod1[10];
HttpMethod2[] Methods2 = new HttpMethod2[10];
var res1 = Methods1.Contains("blah"); //works
var res2 = Methods2.Contains("blah"); //doesn't work
}
public struct HttpMethod1
{
public static implicit operator HttpMethod1(string method)
{
return new HttpMethod1();
}
public static implicit operator string (HttpMethod1 method)
{
return "";
}
}
public class HttpMethod2
{
public static implicit operator HttpMethod2(string method)
{
return new HttpMethod2();
}
//Comment out this method and it works fine
public static implicit operator string (HttpMethod2 method)
{
return "";
}
}
Things I know:
Plainly the problem is in type inference.
In the first case, T is deduced to be HttpMethod1.
In the struct case, there is no conversion from HttpMethod1[] to IEnumerable<string> because covariance only works on reference types.
In the class case, there is no conversion from HttpMethod2[] to IEnumerable<string> because covariance only works on reference conversions, and this is a user-defined conversion.
Things I suspect but need to confirm:
Something about the slight difference between my last two points is confusing the type inference algorithm.
UPDATE:
It has nothing to do with covariant array conversions. The problem repros even without array conversions.
It does however have to do with covariant interface conversions.
It has nothing to do with strings. (Strings are often a bit weird because they have a hard-to-remember conversion to IEnumerable<char> that occasionally messes up type inference.)
Here's a program fragment that displays the problem; update your conversions to convert to C instead of string:
public interface IFoo<out T> {}
public class C {}
public class Program
{
public static bool Contains<T>(IFoo<T> items, T item)
{
System.Console.WriteLine(typeof(T));
return true;
}
public static void Main()
{
IFoo<HttpMethod1> m1 = null;
IFoo<HttpMethod2> m2 = null;
var res1 = Contains(m1, new C()); //works
var res2 = Contains(m2, new C()); //doesn't work
}
}
This looks like a possible bug in type inference, and if it is, it is my fault; many apologies if that is the case. Sadly I do not have time to look into it further today. You might want to open an issue on github and have someone who still does this for a living look into it. I would be fascinated to learn what the result was, and if it turns out to be a bug in either the design or the implementation of the inference algorithm.
Firstly, this is an observed behavioural difference between structs and classes. The fact that you have 'sealed' your class does not affect the outcome in this scenario.
Also we know the following statement will compile as expected for HttpMethod type declared as both a struct and class, thanks to the implicit operator.
string method = HttpMethods[0];
Dealing with Arrays introduces some lesser understood compiler nuances.
Covariance
When HttpMethod is a class (reference type), with an array such as HttpRoute.HttpMethods Array covariance (12.5 C# 5.0 Language Spec) comes into play that allows HttpMethod[x] to be treated as an object. Covariance will respect inbuilt implicit reference conversions (such as type inheritance or conversion to object) and it will respect explicit operators, but it will not respect or look for user defined implicit operators. (While a bit ambigous the actual spec doc lists specifically default implicit operators and explicit operators, it does not mention the user defined operators but seeing everything else is so highly specified you can infer that user defined operators are not supported.)
Basically Covariance takes precedence over many generic type evaluations. More on this in a moment.
Array covariance specifically does not extend to arrays of value-types. For example, no conversion exists that permits an int[] to be treated as an object[].
So when HttpMethod is a struct (value type), covariance is no longer an issue and the following generic extension from System.Linq namespace will apply:
public static bool Contains<TSource>(this IEnumerable<TSource> source, TSource value);
Because you have passed in a string comparator, the Contains statement will be evaluated as follows:
public static bool Contains<string>(this IEnumerable<string> source, string value);
When HttpMethod is a class (Reference Type), thanks to covariance, HttpMethod[] in it's current form comparable only with Object[] and thus IEnumerable, but not IEnumerable< T >, Why not? because the compiler needs to be able to determine the type to generate the generic implementation of IEnumerable< T > and to determine if it can perform an explicit cast from object to T.
Put another way, Compiler cannot determine if T can definetly be a String or not, so it doesn't find the match in the Linq extension methods that we were expecting.
So what can you do about it? (! Not this !)
The first common attempt might be to try using .Cast< string >() to cast the HttpMethod instances to strings for the comparison:
return HttpMethods.Cast<string>().Contains(request.Method) && request.Url.AbsolutePath.StartsWith(Prefix);
You will find that this does not work. Even though The parameter for Cast< T > is of type IEnumerable, not IEnumerable< T >. It is provided to allow you to use older collections that do not implement the generic version of IEnumerable with LINQ. Cast< T > is only designed to convert non-generic objects to their "true" type through the process of evaluating common origins for reference types or Un-Boxing for value types. If Boxing and Unboxing (C# Programming Guide) only applies to value types (structs) and since our HttpMethod type is a reference type (class) the only common origin between HttpMethod and String is Object. On HttpMethod there is no implicit, or even explicit operator that accepts Object and as it is not a value type there is no in built un-box operator that the compiler can use.
Note that this Cast<> will fail at runtime in this scenario when HttpMethod is a value type (class) the compiler will be happy to let it build.
Final Workaround
Instead of Cast< T > or relying on implicit conversions we will need to force the elements in the HttpMethods array to be explicitly cast to string (This will still use out implicit operator!) but Linq again makes this a trivial, but necessary task:
return HttpMethods.Select(c => (string)c).Contains(request.Method) && request.Url.AbsolutePath.StartsWith(Prefix);
Related
I'm experimenting with custom integer types and came across an interesting issue involving generics, implicit conversions, and 32 bit integers.
Below is a stripped down example of how to reproduce the problem. If I have two implicit methods that convert int to MyInt and vice versa, I get a compilation error which looks like C# can't resolve which generic type to use. And it only happens with int or uint. All other integer types work fine: sbyte,byte,short,ushort,long,ulong.
If I remove one of the implicit conversion methods, it also works fine. Something to do with circular implicit conversions?
using Xunit;
public class MyInt
{
public int Value;
//If I remove either one of the implicit methods below, it all works fine.
public static implicit operator int(MyInt myInt)
{
return myInt.Value;
}
public static implicit operator MyInt(int i)
{
return new MyInt() { Value = i };
}
public override bool Equals(object obj)
{
if (obj is MyInt myInt)
{
return this.Value == myInt.Value;
}
else
{
int other_int = (int)obj;
return Value == other_int;
}
}
}
Below is the test code showing the compilation errors I get when both implicit methods are defined.
public class Test
{
[Fact]
public void EqualityTest()
{
MyInt myInt = new MyInt();
myInt.Value = 4 ;
Assert.Equal(4, myInt.Value); //Always OK which makes sense
//Compile errors when both implicit methods defined:
// Error CS1503 Argument 1: cannot convert from 'int' to 'string',
// Error CS1503 Argument 2: cannot convert from 'ImplicitConversion.MyInt' to 'string'
Assert.Equal(4, myInt);
}
}
I believe C# is complaining about not being able to convert both types to string as that is the type of the last Xunit.Assert.Equal() overload and all the others failed to match:
//Xunit.Assert.Equal methods:
public static void Equal<T>(T expected, T actual);
public static void Equal(double expected, double actual, int precision);
public static void Equal<T>(T expected, T actual, IEqualityComparer<T> comparer);
public static void Equal(decimal expected, decimal actual, int precision);
public static void Equal(DateTime expected, DateTime actual, TimeSpan precision);
public static void Equal<T>(IEnumerable<T> expected, IEnumerable<T> actual, IEqualityComparer<T> comparer);
public static void Equal<T>(IEnumerable<T> expected, IEnumerable<T> actual);
public static void Equal(string expected, string actual, bool ignoreCase = false, bool ignoreLineEndingDifferences = false, bool ignoreWhiteSpaceDifferences = false);
public static void Equal(string expected, string actual);
I don't think I've made a mistake with the implicit conversions as I can make other similar examples create the same problem when used with 32 bit ints.
I'm testing in a .NET Core 3.0 project.
Any help would be appreciated. Thanks!
Clarification:
What I would like to know is why this only fails with 32 bit integers. Implicit conversions are working (confirmed with debugging) when the types are anything else like the example below using a long.
using Xunit;
public class MyLong
{
public long Value;
public static implicit operator long(MyLong myInt)
{
return myInt.Value;
}
public static implicit operator MyLong(long i)
{
return new MyLong() { Value = i };
}
public override bool Equals(object obj)
{
if (obj is MyLong myInt)
{
return this.Value == myInt.Value;
}
else
{
long other_int = (long)obj;
return Value == other_int;
}
}
}
public class Test2
{
[Fact]
public void EqualityTest()
{
MyLong myLong = new MyLong();
myLong.Value = 4 ;
Assert.Equal(4, myLong); //NOTE! `4` is implicitly converted to a MyLong
//object for comparison. Confirmed with debugging.
}
}
Something to do with circular implicit conversions?
Yes (though, you've already demonstrated that much by showing that it works fine when one of the conversions is eliminated).
The reason this is happening with int, and not with other types, is that the type of your literal is int. This means that during overload resolution, the compiler can go either way: convert int to MyInt, or convert MyInt to int. Neither option is clearly "better" than the other, so neither of those conversions survive consideration.
Then, having ruled out the closest possible generic version of the method, of the remaining overloads available the only one left is the Equal(string, string) overload (the only other one left with just two parameters is the Equal<T>(IEnumerable<T>, IEnumerable<T>), which is "worse" than the Equal(string, string) overload according to the overload resolution rules). Having found exactly one method that is clearly "better" than any others, the compiler then tries to use that method with your parameters, which of course don't fit, causing the errors to be emitted.
On the other hand…
When you try to call Equal(4, myLong), you've got two incompatible types. A literal having type int, and the MyLong value. In this case, the compiler tries each parameter one by one and finds that when it uses the MyLong type as the type parameter, it is possible to promote the int literal to a long and then implicitly convert that to MyLong. But it can't go the other way. It's not possible to select int as the generic type parameter, because MyLong can't be implicitly converted to int. So in that case, there is a "better" overload to choose, and so it's chosen.
By explicitly specifying the literal's type, you can try different combinations and see this pattern at work. First, I prefer a simpler wrapper class to test with:
public class Wrapper<T>
{
public T Value;
public static implicit operator T(Wrapper<T> wrapper) => wrapper.Value;
public static implicit operator Wrapper<T>(T value) => new Wrapper<T> { Value = value };
}
Then try these:
Wrapper<int> w1 = new Wrapper<int> { Value = 4 };
Wrapper<long> w2 = new Wrapper<long> { Value = 4 };
Assert.Equal(4, w1); // error
Assert.Equal((short)4, w1); // no error
Assert.Equal(4, w2); // no error
Assert.Equal(4L, w2); // error
The only thing that makes int special is that that's the default type for the numeric literal. Otherwise, a type that wraps int works exactly the same as a type that wraps anything else. As long as a conversion is available only in one direction between the two parameters, everything's fine. But when the conversion is available in both directions, the compiler has no choice but to throw up its hands and give up.
I came across this problematic quite often: I like to overload some method with same parameters for different return types, but .NET refuses generic constraints to sealed classes/primitives. I'll refer to this pattern as phantom generics.
I know an ugly workaround: Putting every single interface the type implements behind the where statement.
My Question: Is there any way to use explicit types in generics to illustrate the return type and keep methods distinct?
Here is my code:
public static class Reinterpret {
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe float Cast<T>(int value) where T : float { //'float' is not a valid constraint. A type used as a constraint must be an interface, a non-sealed class or a type parameter.
return *((float*)&value); //reinterpret the bytes of 'value' to a float
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe float Cast<T>(uint value) where T : float { //'float' is not a valid constraint. A type used as a constraint must be an interface, a non-sealed class or a type parameter.
return *((float*)&value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe double Cast<T>(long value) where T : double { //'double' is not a valid constraint. A type used as a constraint must be an interface, a non-sealed class or a type parameter.
return *((double*)&value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe double Cast<T>(ulong value) where T : double { //'double' is not a valid constraint. A type used as a constraint must be an interface, a non-sealed class or a type parameter.
return *((double*)&value);
}
}
Here's one slightly different way of approach it:
// Constraints just to be vaguely reasonable.
public static class Reinterpret<T> where T : struct, IComparable<T>
{
public T Cast(int value) { ... }
public T Cast(uint value) { ... }
public T Cast(float value) { ... }
public T Cast(double value) { ... }
// etc
}
For the implementation, you could just have a Func<int, T> field, a Func<double, T> field etc, and then have a big static constructor:
static Reinterpret()
{
if (typeof(T) == typeof(int))
{
// Assign all the fields using lambda expressions for ints.
// The actual assignment might be tricky, however - you may
// need to resort to some ghastly casting, e.g.
castDouble = (Func<double, T>)(Delegate)(Func<double, int>)
x => *((double*)&value;
}
....
}
Then for any type you didn't want to support, the fields would be null. Each Cast method would look like:
if (castIntMethod != null)
{
return castInt(value);
}
throw new InvalidOperationException("...");
To be honest, this isn't something I'd really want to do. I'd generally just use BitConverter. But it's an option.
Generics are not templates. They do not act like templates. They cannot be made to act like templates.
A "phantom" generic parameter is not going to help you simulate templates (and reinterpret_cast is not an actual template, anyway), because you soon are going to run into the fact that generics do not support specialization.
In particular, you asked "Is there any way to use explicit types in generics to ... keep methods distinct?" and commented that "the generic constraints ... keeps [sic] the methods distinct". But they actually do not. These methods are distinct only because the argument types are different. Generics are computed from overloads, they do not influence overloading.
How can I implement a struct so that the following cast can be performed?
var a = new StatusedValue<double>(1, false);
var b = (StatusedValue<int>)a;
My implementation should behave similarly to Nullable<T>, which works fine. However, this code fails with System.InvalidCastException:
public struct StatusedValue<T> where T : struct
{
public StatusedValue(T value) : this(value, true)
{
}
public StatusedValue(T value, bool isValid)
{
this.value = value;
this.isValid = isValid;
}
private T value;
private bool isValid;
public static implicit operator StatusedValue<T>(T value)
{
return new StatusedValue<T>(value);
}
public static explicit operator T(StatusedValue<T> value)
{
return value.value;
}
}
Result:
Unable to cast object of type 'StatusedValue`1[System.Double]' to type
'StatusedValue`1[System.Int32]'.
This works for Nullable<T> types because they get special treatment from the compiler. This is called a "lifted conversion operator", and you cannot define your own.
From section 6.4.2 of the C# Specification:
6.4.2 Lifted conversion operators
Given a user-defined conversion operator that converts from a non-nullable value type S to a
non-nullable value type T, a lifted conversion operator exists that
converts from S? to T?. This lifted conversion operator performs an
unwrapping from S? to S followed by the user-defined conversion from S
to T followed by a wrapping from T to T?, except that a null valued
S? converts directly to a null valued T?. A lifted conversion operator
has the same implicit or explicit classification as its underlying
user-defined conversion operator. The term “user-defined conversion”
applies to the use of both user-defined and lifted conversion
operators
If you're happy calling a method, try
public StatusedValue<U> CastValue<U>() where U : struct
{
return new StatusedValue<U>((U)Convert.ChangeType(value, typeof(U)), isValid);
}
This will unfortunately throw at runtime rather than compile time if T cannot be converted to U.
Edit: As pointed out below, if you constrain to IConvertible as well as/instead of struct then every conversion is theoretically possible at compile time, and you'll only get a runtime failure because of bad runtime values.
Nullables are specially handled by the compiler, I don't know if this is the case here.
Your operators would allow this:
StatusedValue<int> b = (int)a;
which is probably not what you want, because IsValid is not copied this way.
You could implement an extension method like this:
public static StatusedValue<TTarget> Cast<TSource, TTarget>(this StatusedValue<TSource> source)
where TTarget : struct
where TSource : struct
{
return new StatusedValue<TTarget>(
(TTarget)Convert.ChangeType(
source.Value,
typeof(TTarget)),
source.IsValid);
}
b = a.Cast<int>();
But the compiler cannot check if the types are compatible. ChangeType also returns an object, thus boxing your value.
The answer to why it's like this has already been posted and marked as the answer.
However, you can simplify the syntax to make it easier and clearer to do this while retaining compile-time type-safety.
Firstly, write a helper class to avoid having to specify redundant type parameters:
public static class StatusedValue
{
public static StatusedValue<T> Create<T>(T value, bool isValid = true) where T: struct
{
return new StatusedValue<T>(value, isValid);
}
}
Next you need to expose the underlying value with a Value property (otherwise you can't cast it from code).
Finally you can change your original code from this:
var a = new StatusedValue<double>(1, false);
var b = (StatusedValue<int>)a;
To this:
var a = StatusedValue.Create(1.0, false);
var b = StatusedValue.Create((int)a.Value, false);
where you are doing a simple cast on a.Value.
For a workaround, you will need to provide a way for converting from one underlying type to the other, since the compiler won't be able to figure that out:
public StatusedValue<TResult> To<TResult>(Func<T, TResult> convertFunc)
where TResult : struct {
return new StatusedValue<TResult>(convertFunc(value), isValid);
}
You can then do:
var a = new StatusedValue<double>(1, false);
var b = a.To(Convert.ToInt32);
With some reflection you could build a lookup table of the Convert methods, and lookup the right one based on the type arguments, and then you could default the conversion function to null and if it's not provided, try to lookup the correct conversion automatically. This would remove the clumsy Convert.ToInt32 part, and simply do var b = a.To<int>();
As Rawling points out, Convert.ChangeType can be used. This would make my method look like:
public StatusedValue<T2> To<T2>(Func<T, T2> convertFunc = null)
where T2 : struct {
return new StatusedValue<T2>(
convertFunc == null
? (T2)Convert.ChangeType(value, typeof(T2))
: convertFunc(value),
isValid
);
}
If you don't need a casting, you can add a method like this:
public StatusedValue<int> ConvertToStatusedInt() {
return new StatusedValue<int>(Convert.ToInt32(value), isValid);
}
As suggested in comment:
public StatusedValue<Q> ConvertTo<Q>() where Q:struct {
return new StatusedValue<Q>((Q)Convert.ChangeType(value, typeof(Q)), isValid);
}
TL;DR: (the title gives it away) Can I "Implicitly drop the generic argument from List<T>" in one single conversion?
A friend asked me today if it would be possible to implicitly convert a List<T> to a non-generic wrapper.
var list = new List<_some_type_>();
ObjectResult result = list;
The method would look something like this:
public static implicit operator ObjectResult(List<T> list) { ... }
Clearly, the T here is not defined, and the implicit operator's method name is the type name, ergo you can't include a generic parameter to the method name unless the type were actually generic, i.e.:
class ObjectResult<T> { ... }
Instead of
class ObjectResult { ... }
The constraints we have with user-defined conversions are (am I missing any?):
Cannot convert to or from a Base type
Cannot convert to or from an interface.
Must make conversion enclosed in one of the two types.
What makes List<T> so hard:
List<T>'s only derivation comes from Object; thus we'd have to convert directly from List<T>
List<T> has only interfaces, again, must be directly from List<T>
List<T>, obviously, is compiled up in the framework, so, it must be from our wrapper
I thought of a 2-step solution where there is a middle man we can convert from (whereas the only middle man with List<T> is Object, and due to rule #1, that's not an option).
public class ObjectResult
{
public static implicit operator ObjectResult(WrapperBase arg) { ... }
}
public class WrapperBase { }
public class ObjectResultWrapper<T> : WrapperBase
{
public static implicit operator ObjectResultWrapper<T>(List<T> arg) { ... }
}
Then, the invoking code would look like this:
var list = new List<int>();
ObjectResultWrapper<int> wrap = list;
ObjectResult result = wrap;
This doesn't solve the problem really, it's only a work around to drop T implicitly (but in two steps, not one). At this point, it'd be easier to have a helper method, and not use user-defined conversions.
There may be arguments against the goal of implicitly dropping the generic argument - I don't have anything else of why he feels this was important. Consider this simply an academic question.
The answer: No, You can't do that with an implicit cast.
Alternatives:
I think the best thing would be a static ObjectWrapper.FromList<T>(List<T>) method.
The wrapper cast is an option as well, though not nearly as elegant.
How about declaring a static "Convert" function instead of trying to declare a conversion operator? Then you could use the compiler's type inference do something like this (calling the conversion method From):
List<int> list = new List<int>();
ObjectResult result = ObjectResult.From(list);
The From method might look like this:
public class ObjectResult
{
//...
public static ObjectResult From<T>(T arg) { return new ObjectResult<T>(arg); }
//...
}
public class ObjectResult<T> : ObjectResult
{
//...
public ObjectResult(T obj) { /* ... some implementation ... */ }
//...
}
Using this type:
class Foo
{
public static implicit operator int(Foo obj)
{
return 5;
}
}
var test=new[] { new Foo() };
The following works as expected
var ok=test.Select(x => (int)x).ToList();
but using Cast<> fails with an InvalidCastException - why?
var fail=test.Cast<int>().ToList();
Read Jon Skeet's blog about reimplementing Linq (EduLinq), specifically part 33, where he says this:
It's worth noting that (as of .NET 3.5 SP1) Cast and OfType only perform reference and unboxing conversions. They won't convert a boxed int to a long, or execute user-defined conversions. Basically they follow the same rules as converting from object to a generic type parameter. (That's very convenient for the implementation!)
Casting operators are purely C# compiler level features, the run-time doesn't know anything about them so there is no simple way to implement this via generic Cast method. One way to do this is to perform run-time code generation:
public static class Converter<TSource, TResult>
{
static Converter()
{
var sourceParameter = Expression.Parameter(typeof(TSource));
var conversionExpression = Expression.Lambda<Func<TSource, TResult>>(
Expression.Convert(sourceParameter, typeof(TResult)),
sourceParameter);
Instance = conversionExpression.Compile();
}
public static Func<TSource, TResult> Instance
{
get;
private set;
}
}
public static class EnumerableEx
{
public static IEnumerable<TResult> Cast<TSource, TResult>(this IEnumerable<TSource> source)
{
return source.Select(Converter<TSource, TResult>.Instance);
}
}
but then you'll loose compile-time checking:
var test = new[] { new Foo() };
var ok = test.Cast<Foo, int>().ToList(); // compiles and works ok
var error = test.Cast<Foo, double>().ToList(); // compiles but fails at run-time
Another way is to use reflection as in Puzzling Enumerable.Cast InvalidCastException but this will not work with built-in conversions like from int to long.
The documentation for Enumerable.Cast is actually a bit vague on that and talks about cast and conversion. It does however say that "If an element cannot be cast to type TResult, this method will throw an exception" and your class Foo can't be cast to int but can be converted using cast syntax. The latter is a method call.
Usually Cast and OfType work similar to 'as' an 'is' and if you wrote:
var foo = new Foo()
var bar = foo is int;
bar would be false. It would seem that Cast is consistent with that (though the documentation found on MSDN is not entirely). and fails when the is-operator would return false. (There are one special case where this will not be the case and that's if the value in the sequence is null and T is a reference type)