I've seen this syntax a couple times now, and it's beginning to worry me,
For example:
iCalendar iCal = new iCalendar();
Event evt = iCal.Create<Event>();
It's a Generic Method, Create is declared with type parameters, and check this links for more information:
An Introduction to C# Generics
Generics (C# Programming Guide)
Generic Methods
It's calling a generic method - so in your case, the method may be declared like this:
public T Create<T>()
You can specify the type argument in the angle brackets, just as you would for creating an instance of a generic type:
List<Event> list = new List<Event>();
Does that help?
One difference between generic methods and generic types is that the compiler can try to infer the type argument. For instance, if your Create method were instead:
public T Copy<T>(T original)
you could just call
Copy(someEvent);
and the compiler would infer that you meant:
Copy<Event>(someEvent);
It's the way you mention a generic method in C#.
When you define a generic method you code like this:
return-type MethodName<type-parameter-list>(parameter-list)
When you call a generic method, the compiler usually infers the type parameter from the arguments specified, like this example:
Array.ForEach(myArray, Console.WriteLine);
In this example, if "myArray" is a string array, it'll call Array.ForEach<string> and if it's an int array, it'll call Array.ForEach<int>.
Sometimes, it's impossible for the compiler to infer the type from the parameters (just like your example, where there are no parameters at all). In these cases, you have to specify them manually like that.
It is a generic method that implements the Factory Method pattern.
This syntax is just applying generics to a method. It's typically used for scenarios where you want to control the return type of the method. You will find this kind of syntax a lot in code that uses a IoC framework.
Related
In my code I have declared an interface as follows:
interface IGeneric
{
T GetOfType<T>();
}
And I want to invoke the interface's method with a generic type only known at runtime. This is how I do it currently, and it works:
Type genericArgument = ...
object interfaceImplementation = ...
MethodInfo methodInfo = typeof(IGeneric).GetMethod("GetOfType").MakeGenericMethod(genericArgument);
methodInfo.Invoke(interfaceImplementation, null);
but because I have to call this part of code quite often, I would like to cache the method info in a delegate. I tried this delegate definition
private delegate T GetOfTypeDelegate<T>();
and tried to create a delegate using the method info I retrieved like shown above like this:
GetOfTypeDelegate<?> deleg = (GetOfTypeDelegate<?>) Delegate.CreateDelegate(typeof(GetOfTypeDelegate<?>), methodInfo);
but since I don't know the type of the generic argument at compile time, I don't know what to put where I used the ? or how to make this work at all.
Any help is gladly appreciated.
I'd advise having generic and non-generic versions of the method, much like List<T> implements IEnumerable<T> while also explicitly implementing System.Collections.IEnumerable.
"Type known only at runtime" is exactly what generics aren't intended to be used for. The way you're calling this method, you only ever get object out of it anyway. Better to have a real ordinary non-generic method that just returns object.
T GetOfType<T>();
object GetOfType(Type t);
You don't even need to worry about overload resolution. There's some extra burden placed on the class implementing the interface, admittedly. But as you've seen, there's going to be a burden somewhere.
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.
I define a Delegate type like :
delegate void DrawShape(Brush aBrush,Rectangle aRect);
Would you tell me why the below below methods of creating delegate object are all correct:
DrawShape DrawRectangleMethod = CreateGraphics().FillRectangle;
DrawShape AnotherDrawRectangleMethod = new DrawShape(CreateGraphics().FillRectangle);
Why can the method without "New" work correctly?
DrawShape DrawRectangleMethod = CreateGraphics().FillRectangle;
is possible thanks to C#2's implicit method group conversions which are spec'd here.
C# is smart enough to handle method groups for you. A method group is the method name without the parentheses; there may be many overloads of the method with different signatures, but the "base" name without parentheses is called the method group. The compiler will insert the constructor call for you, allowing you to write a more concise line of code.
Cause the compiler will automatically insert it for you. It's just syntactic sugar.
Simply take a look into Jons Bluffer's Guide at chapter Delegates.
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 this common code:
private bool DoItStartup(IReader reader, Type provider)
{
/// lots of common boiler plate code
/// like:
var abcProvider = reader.ReaderData as AbcProvider;
var xyzProvider = abcProvider.Provisions.FirstOrDefault<XyzProvider>(); // line 2
}
The above lines of code are there for like 50 or some providers, now Line 2 I want to basically do this:
var xyzProvider = abcProvider.Provisions.FirstOrDefault<typeOf(provider)>();
This doesn't work, possibly because xyzProvider doesn't know it's type # compile time? Not sure. But is there a similar pattern I can use. Otherwise I'm having to duplicate this cruft code 50 times :(
Without knowing the type of abcProvider.Provisions it's a bit hard to say for sure... but normally I don't provide any type arguments to FirstOrDefault... I just let type inference work.
Have you tried just calling:
var xyzProvider = abcProvider.Provisions.FirstOrDefault();
?
(The reason it's not working is that type arguments have to be names of types or type parameters; they can't be expressions computed at execution time.)
It sounds like you need to provide a generic parameter to either the method or the class that encloses the code above. The following should work properly (not sure how provider is being passed in
public T GetStuff() {
var xyzProvider = abcProvider.Provisions.FirstOrDefault<T>();
}
You might need to use Generics.
There are several articles on the MSDN that cover this:
Generics (C# Programming Guide)
An Introduction to C# Generics
Generic Methods (C# Programming Guide)
Generic parameters of generic types are determined at compile type (not run time). But you want your code to get type of FirstOrDefault at runtime which causes the error.
Try using this instead:
private bool DoItStartup<T>(IReader reader, Type provider)
{
...
var x=list.FirstOrDefault<T>();
}