C# Variance Issue with IEnumerable<T> vs <T> [duplicate] - c#

This question already has answers here:
Method overload resolution with regards to generics and IEnumerable
(2 answers)
Closed 8 years ago.
So, I'm having an issue with similar code to below:
public static String MyFunc<T>(this IEnumerable<T> list) where T : struct
{
... some code ...
return myString;
}
public static String MyFunc<T>(this T o) where T : struct
{
... some code ...
return myString;
}
The problem is that when trying to do call MyFunc on a List it uses the second function instead of the one that accepts an IEnumerable. I know this has to do with variance, but I'm uncertain as to how to force it to use the first function rather than the second. The code I would use to call the first one would be:
List<int> x = new List<int>();
String s = x.MyFunc();
The above code immediately goes to the second function and I need it to use the first. How can I force the desired behavior? Incidentally, I'm using .NET 4.0

The reason that it's currently picking the second method is that a conversion from a type to itself (second method, T=List<int>, conversion from List<int> to List<int>) will always be "better" than a conversion to the type it implements (first method, T=int, conversion from List<int> to IEnumerable<int>). This has nothing to do with variance, by the way - it's just the method overloading algorithm and type inference.
Note that with your current code, although the second overload is picked, it will then be found to be invalid because T violates the T : struct constraint. The constraint is only checked after the overload is chosen. See Eric Lippert's blog post on this for more details.
I suggest you just give the two methods different names.
EDIT: As noted by Anthony in comments, this can work if you call it as:
x.AsEnumerable().MyFunc();
Or just change the declaration to:
IEnumerable<int> x = new List<int>();
x.MyFunc();
It's not entirely clear to me exactly why it's better here - in this case after type argument substitution, you've basically got IEnumerable<T> as the parameter type in both cases. However, I would still strongly recommend using different names here. The fact that it's got me puzzling over the spec to work out which overload is being called should be enough indication that the behaviour won't be immediately clear to everyone reading the code.
EDIT: I think the reason is here (from the C# 5 spec, section 7.5.3.2):
A type parameter is less specific than a non-type parameter
So just T is less specific than IEnumerable<T>, even though the latter involves a type parameter. It's still not clear to me whether this is the language designers' intended behaviour... I can see why a type which involves type parameters should be seen as less specific than a type which doesn't involve type parameters, but not quite this wording...

Related

Why can't the compiler infer this type argument from usage

This question is based off of the results from another SO question of mine. My new question is not a question of how can I get X to work, but why doesn't X work.
I've created a simplified example of my problem, however if you want to see the practical application/situation I'm using this, look at my original question (the below functions don't actually do anything useful).
T bar<T>(Func<T, bool> f) { return default(T); }
bool foo(int i) { return true; }
Now I have 3 lines of code that do work as expected and all do the same thing purpose wise.
int num;
num = bar<int>(foo);
num = bar(new Func<int, bool>(foo));
num = bar((int i) => true );
My question is "Why do I need to explicitly specify T for bar for the first example?" The reason I wonder this is because the compiler turns the first two examples into the same line of code. Using ILSpy I see that the code compiles to this.
num = Program.bar<int>(new Func<int, bool>(Program.foo));
num = Program.bar<int>(new Func<int, bool>(Program.foo));
num = Program.bar<int>((int i) => true);
I don't understand why the compiler can't infer the type from the fact that I only have one function called foo, and it does fit the template so to speak. Now if I had created another function bool foo(bool i) I would understand if the compiler complained that there was some ambiguity and it didn't know which one I wanted and that I should specify the type argument explicitly.
This of course is just me being lazy, but it is just something I was expecting and was surprised when the compiler wasn't picking up my slack.
I'm on the bus, so, short answer.
type inference of t requires knowing the formal parameter type of the delegate type in the argument.
conversion of the method group to the delegate type does overload resolution as though the method group was invoked with the arguments of the formal parameter types of the target delegate.
but those types are what we are trying to deduce!
this is circular reasoning, so type inference rejects it. A method group conversion requires that the formal parameter types be deduced from some other argument.
you have no other arguments.
so inference fails.
that the group contains only one method is irrelevant. It would be bizarre if adding more methods to the group caused inference to fail. The rule that a group of overloads is resolved through overload resolution is a sensible one, and that requires knowing the parameters. You don't get to run the inferences backwards just because a method group happens to be a singleton.
see the type inference tag on my msdn blog for a longer article on this topic.
http://blogs.msdn.com/b/ericlippert/archive/2007/11/05/c-3-0-return-type-inference-does-not-work-on-member-groups.aspx

Why doesn't the C# compiler resolve Delegate types only different in return type when passing a method group as parameter? [duplicate]

This question already has answers here:
Compiler Ambiguous invocation error - anonymous method and method group with Func<> or Action
(4 answers)
Closed 9 years ago.
Please consider the following code:
class Program
{
static void Foobar() { }
static void Test(Action a) { }
static void Test(Func<bool> a) { }
static void Main(string[] args)
{
Test(Foobar);
}
}
It does not compile on VS2012. The compiler complains, that the reference to the method Foobar in the line Test(Foobar) is ambigious. This is the whole error message I get:
The call is ambiguous between the following methods or properties:
'Program.Test(System.Action)' and 'Program.Test(System.Func<bool>)'
Now, the fix would be to just cast Foobar into an Action to force the correct overload: Test((Action)Foobar).
But I am interested in the reason, why C# can't figure this out by himself? Why does he have to think that a Func<bool> would be an valid overload for a void()-function?
I know that you can not overload a method with another method that only differs in its return type. But that does not seem to be the case here. I am not overloading Foobar(). Sure, the return value may not be part of Foobar's signature, but why does this matter when it comes to convertion from method groups into delegates?
I am also aware of the problem, that the compiler sometimes refuses to cast method groups with overloaded methods into specific delegates, even if he could have all the information he needs, but I think that is a different problem (and a different error message). Again - Foobar is not overloaded. Only Test() is.
Edit: As Matthew pointed out, the problem is the same as the linked question. However, I am not 100% satisfied with the (very good) answer that Eric Lippert and Jon Skeet gave there.
In one part of his answer, Eric says:
The principle here is that determining method group convertibility requires selecting a
method from a method group using overload resolution, and overload resolution does
not consider return types.
Any clue why is that? To me, it seems that a solution to the problem is exactly to change this sentence above and also consider the return type when choosing methods from a method group. Period, finished and everyone is happy, no? ;)
A practical example why this ambigious error sucks is, that Task.Run() can not be used on void()-methods of the own class without a cast. So even in some MSDN examples I saw, they used Task.Run(() => Foobar()) instead of the much cleaner Task.Run(Foobar).
Because both delegates could be called without any parameter:
Action action = new Action(() => ...);
Func<bool> func = new Func<bool>(() => true);
action();
func(); // Legal even if you ignore the return value
The return type is not taken into account to resolve the overload.

Why can't I use linq's Cast with user-defined casts but I can use it with a Select call? [duplicate]

This question already has answers here:
LINQ .Cast() extension method fails but (type)object works
(3 answers)
Closed 9 years ago.
I recently had a problem using it user-defined casts (cast operator overload) alongside linq's Cast method.
I found a similar question about my problem here at SO and I also found a link that explains it well. My problem is solved.
But something kept me wondering:
Why this doesn't work:
foolist.Cast<bar>(); // throws InvalidCastException
while this works:
foolist.Select(f => (bar)f).ToList(); // works fine
I believe that it's something related to the implementation of each method. If so, couldn't the Cast method have a similar implementation to Select allowing it to be used with user-defined casts (since this is somewhat expected).
Note: I'm not asking why it fails. I'm asking why the Cast method was written in a way that fails.
The reason why is that the Cast method performs the cast in a generic context
IEnumerable<T> Cast<T>(this IEnumerable e) {
foreach (object cur in e) {
return (T)cur;
}
}
The actual casting logic is verified and emitted at this exact point. This point is in a generic function and has no knowledge of the user defined conversions for the type T is eventually instantiated into. All it has access to is standard CLR style conversions.
In the second example you are doing a cast on the real type (not a generic type parameter). Hence the C# compiler has access to all user defined conversions on that object and can insert the most appropriate one.

Force generic type parameter

I'm building a HTTP-API wrapper for .NET, which has a bunch of methods to set data in an object, and then it serializes the data and sends it to my server. There are 6 datatypes allowed:
string
int
long
float
double
DateTime
My data attributes use generics:
SetAttribute<T>(string key, T value)
So there is only one generic method to set data. Since I cannot constrain the data types to the 6 mentioned, I use run-time checks and throw an exception when the wrong data type is used.
Now for my problem: I have two versions of SetAttribute, one that takes a single value (of type T) and one that takes multiple values (of type IEnumerable<T>). The problem is that when a programmer uses this wrapper and does not specify the type parameter, the runtime guesses which method to use, for instance:
SetAttribute("testkey","thing,anotherthing,athirdthing".Split(','))
This defaults to the single value method and T is String[] which of course makes my method cast an exception because String[] is not a valid type. If you specify:
SetAttribute<string>("testkey","thing,anotherThing,aThirdThing".Split(','))
The runtime chooses the correct method (multi-value) and no exception is cast because T is then string.
My question: how can I label my methods so that the type parameter is mandatory and must be explicitly defined? Or do I have to detect this at runtime and redirect to the multi-method myself?
Ok, this was originally a comment above since it doesn't necessarily answer your original question but suggests an alternate approach;
I would say using a public generic SetAttribute in this case isn't necessarily a good idea.
Since the types are so constrained, you should probably just write the overloads and move the errors from runtime to compile time. It would also allow you to take IEnumerable<string> etc. with another 6 overloads and eliminate the problem you're having entirely.
You can always implement SetAttribute with a private generic and just call that from each overload, that will remove some duplication.
It will also more or less eliminate the need for runtime checks, since the types are already constrained by the compiler.
Given a parameter type, the compiler finds a best match from your overloads. If you cast your string[] to an IEnumerable<string> you will probably find it works as expected because the best match is a method that has exactly those parameters. But you have no method that takes a string[], so given one as a parameter, the compiler makes the best guess it can.
I would have two separately named methods rather than overloads otherwise it is too easy to run into this problem. Or have 6 separate overloads, as #Joachim suggests.
I would suggest a better solution would be to test whether the value passed in is IEnumerable after it fails everything else and treat it as such if it is. (I imagine that you're handling IEnumerable as a seventh case already).
One solution would be to break your original method into 6 non-generic overloads, and add another generic overload for collections:
void SetAttribute(string key, int value);
void SetAttribute(string key, string value);
// etc
// abd this takes care of collections:
void SetAttribute<T>(string key, IEnumerable<T> value);

Using generic constraints with value types

I am experimenting with fluent extension methods.
I have the following simple extension method to perform a safe cast.
public static T As<T>(this Object source)
where T : class
{
return source as T;
}
This worked well, but when I tried to make it intuitive to use valuetypes with an overload
public static T As<T>(this ValueType source)
where T : struct
{
return (T)source;
}
I ran into problems. The method resolution logic always chooses the first method above, and gives a syntax error (accurately) that the struct is not a class.
Is there a way to handle the above, or should I go the route of removing the constraint while testing for and handling all types in the same method?
==== Edit: to answer questions ====
I am compiling this against the 3.5 framework. I'm not really trying to accomplish anything in particular; this is just an experiment with the above. My interest was piqued and I threw together some code.
I'm not particularly concerned with it remaining a 'safe' cast. That is how it started, and can be kept safe with default() -- but that's not really the focus of the question and code to ensure 'safeness' would just obscure.
As to the expressiveness, no value.As<int>() is not any more expressive than (int)value; but why should the user of the method have to 'just know' it only works with reference types? My trying to work it in was more about the expected behavior of the method than expressive writing.
The code snippet value.As<DateTime>(), gives the error "The type 'System.DateTime' must be a reference type in order to use it as parameter 'T' in the generic type or method ....As(object)". From the error message I see it is resolving to use the top method above as it is the one requiring the reference type.
In .NET 4, the second overload is chosen based on your code sample. (Also just tested against .NET 3.5, same result.)
int myInt = 1;
long myLong = myInt.As<long>(); // chooses ValueType version
However, this only gets us to the scene of the next crash. The (T)source; results in an invalid cast exception. You could get around that by writing the method as
public static T As<T>(this ValueType source)
where T : struct
{
return (T)Convert.ChangeType(source, typeof(T));
}
However, I wonder what you're actually looking to achieve, as I do not see the immediate benefit. (And for that matter, this isn't safe like the source as T object version.) For example, how is
long myLong = myInt.As<long>();
Any more expressive or easier to use than
long myLong = (long)myInt;

Categories

Resources