I have the following extension methods for my MessageBus:
public static class MessageBusMixins
{
public static IDisposable Subscribe<T>(
this IObservable<T> observable,
MessageBus bus)
where T:class
{
...
}
public static IDisposable Subscribe<T>(
this IObservable<Maybe<T>> observable,
MessageBus bus)
{
...
}
}
which compiles fine. However when I try to use it:
IObservable<Maybe<string>> source = ...;
MessageBus bus = ...;
source.Subscribe(bus);
I get the error that neither of the two candidate methods
are most specific. However I thought that Maybe<T> would
be more specific than T or is that not correct?
EDIT
It gets curiouser because if I call the extension method
explicitly then:
MessageBus.SubscribeTo(source, bus);
Then it works and picks the correct method.
Well, you can fix it by specifying the type argument:
source.Subscribe<string>(bus);
... as that's now only the second method is applicable.
Otherwise, the compiler could call either of:
source.Subscribe<string>(bus);
source.Subscribe<Maybe<string>>(bus);
If you think the first is more specific than the second, you'll have to find the rule in the C# specification which says so :) It's not an unreasonable expectation, but I don't think the normal "more specific" conversions apply to type parameters as well as regular parameters.
So for example, in section 7.5.3.2 of the C# 4 spec ("Better Function Member") there a rule about:
Otherwise if MP has more specific parameter types than MQ, then MP is better than MQ. [... lots of details about less/more specific ...]
... but there's no similar point about type parameters. (The second about normal parameters talks about type arguments, but that's within the parameter types themselves.)
Another alternative is to simply give the methods different names. Do they have subtly different behaviour? If so, why not make that really obvious via the naming? You really don't want someone to get the wrong behaviour just because they were surprised about which overload was called.
Related
For some reason I have a feeling only Jon Skeet would know the answer to this but it's worth a shot.
I have this method stub which is used as a proxy to generate commands.
public static void SetCommand<T>(string commandName, Action<T> execution)
where T : new()
{
//Omitted unimportant
}
I have a function which is calling this code, but the behavior differs depending on how it's called.
If I call the code by explictly declaring an Action all of the parameter can resolve fine
Action<ClassDeclarationOptions> test = (t) => { };
SetCommand(GENERATE_CLASS_COMMAND, test);
However if I declare a function to represent my action
public static void GenerateClass(ClassDeclarationOptions classOptions)
{
}
Then I need to explictly declare the parameter when passing it to the function like so:
SetCommand<ClassDeclarationOptions>(GENERATE_CLASS_COMMAND, Commands.GenerateClass);
Can someone explain why the compiler cannot resolve my Generic Parameter from Method Definition
Let's say there's an overload on Commands.GenerateClass that takes a different parameter type, for example:
public static void GenerateClass(SomeOtherClass stuff)
{
}
Now there's no way for the compiler to figure out which GenerateClass method to use. However, as soon as you specify the type parameter the ambiguity goes away.
So even if you had a single method and the compiler inferred the type arguments, you could add that second method later on and break existing code without even realising it. Much safer just to force code to be explicit.
Take this interface:
interface ILogger
{
void Store(string payload);
}
And this class implementation of ILogger:
class Logger : ILogger
{
void Store(string payload, bool swallowException = true)
{
...
}
}
I would anticipate the compiler would recognize swallowException as an optional argument, and thus satisfy the requirements of the interface. Instead, what happens is the compiler complains that Logger does not implement interface member Store.
Another interesting thing I tried was implementing the interface explicitly, like so:
class Logger : ILogger
{
void ILogger.Store(string payload, bool swallowException = true)
{
...
}
}
The compiler gives a warning "The default value specified for parameter 'swallowException' will have no effect because it applies to a member that is used in contexts that do not allow optional arguments." It seems to suggest optional arguments are somehow incompatible with explicit interface definitions, but why?
I can work around the problem by overloading Store with two separate function definitions (the way of doing things before optional arguments existed). However I like optional arguments for their syntactic clarity and would prefer that this just worked the way I expect.
I understand there's probably a reasonable (historical or otherwise) explanation for why this is the way it is, but I can't seem to figure it out.
Because optional arguments in C# are just syntactic sugar.
The method definition in your case is
void Store(string payload, bool swallowException)
rather than
void Store(string payload)
Which obviously doesn't match the interface.
The way default arguments work is that the compiler injects the default values into the call of the method. So if you do Store(payload), the compiler will actually emit Store(payload, true). This is extremely important for understanding of default arguments - it's done in compile time of the caller. So if you change the default argument in the callee without recompiling the caller, the caller is still going to use the old default argument.
This also explains the warning you got - since the default value is passed by the compiler explicitly, and you can't call an explicit implementation of an interface without casting to the interface, you're not going to get an opportunity to use the default value, ever.
You don't actually want to use default arguments at all. Simply define two methods like this:
void Store(string payload, bool swallowException)
{
// Do your job
}
void Store(string payload)
{
Store(payload, true);
}
This avoids both of the problems above - the interface contract is satisfied, and the default argument is now part of the callee, not the caller.
Personally, I don't use optional arguments in public API methods at all - they're just aching to cause trouble when you decide that you want to change them at some point. Unless you can make sure they will stay the same forever, don't use them. The same applies to const and enum - both are also determined at compile-time, rather than run-time.
Remember, the reasoning for including default arguments is to allow you to not pass some argument. That makes sense for things like COM API calls (which would otherwise require you to pass all the arguments you don't want to pass as Type.Missing), or null values. Even using false is just asking for trouble when someone decides that a better default would be true - suddenly, some callers are using true and some false, although all think they're using the "default". For a case like yours, I'd use bool? instead, with a default value of null (or default(bool?), whichever you prefer). In the method code itself, you can then easily handle the default at the proper point - say, by doing swallowException.GetValueOrDefault(true).
I'm using BitFactory logging, which exposes a bunch of methods like this:
public void LogWarning(object aCategory, object anObject)
I've got an extension method that makes this a bit nicer for our logging needs:
public static void LogWarning(this CompositeLogger logger,
string message = "", params object[] parameters)
Which just wraps up some common logging operations, and means I can log like:
Logging.LogWarning("Something bad happened to the {0}. Id was {1}",foo,bar);
But when I only have one string in my params object[], then my extension method won't be called, instead the original method will be chosen.
Apart from naming my method something else, is there a way I can stop this from happening?
The rules about how overloaded methods are resolved to one (or an error) are complex (the C# specification is included with Visual Studio for all the gory details).
But there is one simple rule: extension methods are only considered if there is no possible member that can be called.
Because the signature of two objects will accept any two parameters, any call with two parameters will match that member. Thus no extension methods will considered as possibilities.
You could pass a third parameter (eg. String.Empty) and not use it in the format.
Or, and I suspect this is better, to avoid possible interactions with additions to the library (variable length argument list methods are prone to this) rename to LogWarningFormat (akin to the naming of StringBuffer.AppendFormat).
PS. there is no point having a default for the message parameter: it will never used unless you pass no arguments: but that would log nothing.
Declared methods are always preceding extension methods.
If you want to call the extension regardless of the declared method, you have to call it as a regular static method, of the class that declared it.
eg:
LoggerExtensions.LogWarning(Logging, "Something bad happened to the {0}. Id was {1}",foo,bar);
I assume that the extension is declared in a class named LoggerExtensions
Provided that I think a method with a different name is the way to go (easier to read and maintain), as a workaround you could specify parameters as a named parameter:
logger.LogWarning("Something bad happened to the {0}.", parameters: "foo");
Method overloading allows us to define many methods with the same name but with a different set of parameters ( thus with the same name but different signature ).
Are these two methods overloaded?
class A
{
public static void MyMethod<T>(T myVal) { }
public static void MyMethod(int myVal) { }
}
EDIT:
Shouldn't statement A<int>.MyMethod(myInt); throw an error, since constructed type A<int> has two methods with the same name and same signature?
Are the two methods overloaded?
Yes.
Shouldn't statement A<int>.MyMethod(myInt); throw an error, since constructed type A<int> has two methods with the same signature?
The question doesn't make sense; A is not a generic type as you have declared it. Perhaps you meant to ask:
Should the statement A.MyMethod(myInt); cause the compiler to report an error, since there are two ambiguous candidate methods?
No. As others have said, overload resolution prefers the non-generic version in this case. See below for more details.
Or perhaps you meant to ask:
Should the declaration of type A be illegal in the first place, since in some sense it has two methods with the same signature, MyMethod and MyMethod<int>?
No. The type A is perfectly legal. The generic arity is part of the signature. So there are not two methods with the same signature because the first has generic arity zero, the second has generic arity one.
Or perhaps you meant to ask:
class G<T>
{
public static void M(T t) {}
public static void M(int t) {}
}
Generic type G<T> can be constructed such that it has two methods with the same signature. Is it legal to declare such a type?
Yes, it is legal to declare such a type. It is usually a bad idea, but it is legal.
You might then retort:
But my copy of the C# 2.0 specification as published by Addison-Wesley states on page 479 "Two function members declared with the same names ... must have have parameter types such that no closed constructed type could have two members with the same name and signature." What's up with that?
When C# 2.0 was originally designed that was the plan. However, then the designers realized that this desirable pattern would be made illegal:
class C<T>
{
public C(T t) { ... } // Create a C<T> from a given T
public C(Stream s) { ... } // Deserialize a C<T> from disk
}
And now we say sorry buddy, because you could say C<Stream>, causing two constructors to unify, the whole class is illegal. That would be unfortunate. Obviously it is unlikely that anyone will ever construct this thing with Stream as the type parameter!
Unfortunately, the spec went to press before the text was updated to the final version. The rule on page 479 is not what we implemented.
Continuing to pose some more questions on your behalf:
So what happens if you call G<int>.M(123) or, in the original example, if you call A.MyMethod(123)?
When overload resolution is faced with two methods that have identical signatures due to generic construction then the one that is generic construction is considered to be "less specific" than the one that is "natural". A less specific method loses to a more specific method.
So why is it a bad idea, if overload resolution works?
The situation with A.MyMethod isn't too bad; it is usually pretty easy to unambiguously work out which method is intended. But the situation with G<int>.M(123) is far worse. The CLR rules make this sort of situation "implementation defined behaviour" and therefore any old thing can happen. Technically, the CLR could refuse to verify a program that constructs type G<int>. Or it could crash. In point of fact it does neither; it does the best it can with the bad situation.
Are there any examples of this sort of type construction causing truly implementation-defined behaviour?
Yes. See these articles for details:
https://ericlippert.com/2006/04/05/odious-ambiguous-overloads-part-one/
https://ericlippert.com/2006/04/06/odious-ambiguous-overloads-part-two/
Yes. MyMethod(int myVal) will be called when the type of the parameter is an int, the generic overload will be called for all other parameter arguments, even when the parameter argument is implicitly convertible to (or is a derived class of) the hardcoded type. Overload resolution will go for the best fit, and the generic overload will resolve to an exact match at compile time.
Note: You can explicitly invoke the generic overload and use an int by providing the type parameter in the method call, as Steven Sudit points out in his answer.
short s = 1;
int i = s;
MyMethod(s); // Generic
MyMethod(i); // int
MyMethod((int)s); // int
MyMethod(1); // int
MyMethod<int>(1); // Generic**
MyMethod(1.0); // Generic
// etc.
Yes, they are. They will allow code as such:
A.MyMethod("a string"); // calls the generic version
A.MyMethod(42); // calls the int version
Yes, they are overloaded. The compiler is supposed to prefer explicit method signatures against generic methods if they are available. Beware, however, that if you can avoid this kind of overload you probably should. There have been bug reports with respect to this sort of overload and unexpected behaviors.
https://connect.microsoft.com/VisualStudio/feedback/details/522202/c-3-0-generic-overload-call-resolution-from-within-generic-function
Yes. They have the same name "MyMethod" but different signatures. The C# specification, however, specifically handles this by saying that the compiler will prefer the non-generic version over the generic version, when both are options.
Yes. Off the top of my head, if you call A.MyMethod(1);, it will always run the second method. You'd have to call A.MyMethod<int>(1); to force it to run the first.
I have a question that's not really a problem, but something that made me a little curious.
I have a class with two methods in it. One is a static method and the other one is an instance method. The methods have the same name.
public class BlockHeader
{
public static BlockHeader Peek(BinaryReader reader)
{
// Create a block header and peek at it.
BlockHeader blockHeader = new BlockHeader();
blockHeader.Peek(reader);
return blockHeader;
}
public virtual void Peek(BinaryReader reader)
{
// Do magic.
}
}
When I try to build my project I get an error saying:
The call is ambiguous between the
following methods or properties:
'MyApp.BlockHeader.Peek(System.IO.BinaryReader)'
and
'MyApp.BlockHeader.Peek(System.IO.BinaryReader)'
I know that the method signatures are virtually the same, but I can't see how I possibly could call a static method directly from an instance member.
I assume that there is a very good reason for this, but does anyone know what that reason is?
The general policy of the C# design is to force you to specify wherever there is potential ambiguity. In the face of refactoring tools that allow one to rejig whether things are static or not at the drop of a hat, this stance is great - especially for cases like this. You'll see many other cases like this (override vs virtual, new for shadowing etc.).
In general, removing this type of room for confusion will make the code clearer and forces you to keep your house in order.
EDIT: A good post from Eric Lippert discusses another reason for this ambiguity leading to the error you saw
Here's a excerpt from the C# 3.0 language specification.
The signature of a method must be unique in the class in which the method is declared. The signature of a method consists of the name of the method, the number of type parameters and the number, modifiers, and types of its parameters. The signature of a method does not include the return type.
The 'static' modifier is not part of the signature so your example violates this rule of unique signatures.
I don't know the reason behind the rule, though.
I think there's no technical reason to disallow it, but it is done more so to protect the programmer from himself. Consider the following example:
public static void Main()
{
BlockHeader BlockHeader = new BlockHeader();
BlockHeader.Peek();
}
The example above is perfectly valid, but if the situation you describe were allowed, would it be readable? Could you see, in the blink of an eye, whether the instance method or the static method was called?