On MSDN (https://learn.microsoft.com/en-us/dotnet/standard/generics/), it says:
Generic methods can appear on generic or nongeneric types. It is important to note that a method is not generic just because it belongs to a generic type, or even because it has formal parameters whose types are the generic parameters of the enclosing type. A method is generic only if it has its own list of type parameters. In the following code, only method G is generic.
Isn't M for all intents and purposes generic? If you call method M on some instance of type T, M can only have input and output parameters of type T.
Would there be any issues with using such a nongeneric method M?
class A
{
T G<T>(T arg)
{
T temp = arg;
//...
return temp;
}
}
class Generic<T>
{
T M(T arg)
{
T temp = arg;
//...
return temp;
}
}
Isn't M for all intents and purposes generic?
If you use reflection to inspect those methods, you'll find that IsGenericMethod and IsGenericMethodDefinition are true for A.G, and false for Generic<>.M. This is true even though Generic<>.M's return type is T, whose IsGenericParameter property is true.
You're asking a question about semantics (i.e. the linguistic meaning of "generic method"), and Microsoft has defined the meaning of these concepts as they pertain to C#. So when Microsoft says that a generic method is one that takes generic type arguments, that's the definition that's going to be accepted, both by developers and by the framework itself.
If you call method M on some instance of type T, M can only have input and output parameters of type T.
Yes, the difference is in the scope of the type T. For example, if you have an instance of Generic<string>, you cannot pass its M an int. With the generic method, the generic arguments can be changed at the method level, whereas a non-generic method on a generic class uses types that match the generic types of the class that it belongs to.
Would there be any issues with using such a nongeneric method M?
There are no "issues" with using a non-generic method like M inside of a generic class. That's how generic classes were meant to work. Just be aware of the differences in behavior I mentioned above.
Is covariance all about accepting values?
I am learning the C# through the CLR via C# book. And I come across the following excerpt:
Since T is covariant, it is possible to have the following code compile and run successfully:
// This method accepts an IEnumerable of any reference type
Int32 Count(IEnumerable<Object> collection) { ... }
...
// The call below passes an IEnumerable<String> to Count
Int32 c = Count(new[] { "Grant" });
I am confused here. Because the covariance is about having the type which is one of the base types of the required type. And as such the covariance is used only in the context of the return types. While in the example above we have a String (which is derived from Object, so that is contravariant, but not covariant) which is used in the context of passing arguments (but not returning values).
So, should we use in the example above the contravariant instead of the covariant (meaning that there is an error in the book)?
UPDATE
After the comments I got another question. Are the following definitions correct?
Contravariant Meaning that the generic type parameter can change from a class to a class
derived from it. In C#, you indicate contravariant generic type parameters with the in keyword.
Contravariant generic type parameters can appear only in input positions such as a method’s
argument.
Covariant Meaning that the generic type argument can change from a class to one of its base
classes. In C#, you indicate covariant generic type parameters with the out keyword. Covariant
As Josh pointed out the book is correct.
You can check this link if you want to confirm it from another source.
IEnumerable<Cat> is a subtype of IEnumerable<Animal>. The subtyping is preserved because IEnumerable<T> is covariant on T.
The two keywords in C# for those concepts are out for covariant and in for contravariant. In the IEnumerable<T> case this translate to IEnumerable<out T>.
Hope this helps.
UPDATE
You would have to inverse your definitions as follows.
Covariant Meaning that the generic type parameter can be a certain class and all the derived classes from it (IEnumerable<Object> can be a IEnumerable<String> since String is a subtype of Object). In C#, you indicate covariant generic type parameters with the out keyword.
Contravariant Meaning that the generic type argument can change from a
class to one of its base classes. In C#, you indicate contravariant
generic type parameters with the in keyword.
How can I find out the base type of a generic type?
For example
Func<A, B>
I'd like to be able to say this is a Func<> .. but apparently, Func<,> is different from Func<> -- Is there a way to somehow catch them both, or Func<,,,> etc?
You're looking for GetGenericTypeDefinition:
var t = typeof(Func<int, string>);
var tGeneric = t.GetGenericTypeDefinition();
Assert.AreEqual(typeof(Func<,>), tGeneric);
If you then want to know if a type is one of the many Func<> variants, then your best best is simply to do something like this. Checking type names, as suggested elsewhere is absolutely NOT the way to check type identity:
static Type[] funcGenerics = new[]{
typeof(Func<>), typeof(Func<,>), typeof(Func<,,>), typeof(Func<,,,>),
/* and so on... */
}
//there are other ways to do the above - but this is the most explicit.
static bool IsFuncType(Type t)
{
if(t.IsGenericTypeDefinition)
return funcGenerics.Any(tt => tt == t);
else if(t.IsGenericType)
return IsFuncType(t.GetGenericTypeDefinition());
return false;
}
Your terminology is incorrect - which I suspect why you got a downvote on your question. A base type is one that a type inherits from (not an interface, which is different, although conceptually very similar).
A generic type definition is best thought of as being like a template (the strong qualification there because the term 'template' is used in C++ and, while visually similar they are very different in implementation).
More accurately, Func<,> is a generic type definition whereas Func<int, string> is a closed generic (the 'generic type').
You can also have an open generic, which is where the type arguments are generic parameters - e.g, given:
class MyType<T> : List<T> { }
Then List<T> is an open generic with the generic type definition List<>, because T is a generic parameter which will not be closed till MyType<T> is referenced with a concrete type argument, such as int or string.
Finally, just because a bunch of generic types share the same common name, e.g. Func<>, Func<,>, and Func<,,> it does not mean they are in any way related. At the type level, there is no explicit connection, which is why you have to check for all these type identities, and why there is no common 'base' as you put it. If they all had a common interface or base class, however, then you could - by checking for compatibility with that interface or base type.
Given a generic type definition, you can construct generic types using MakeGenericType, as has been mentioned by Jeffrey Zhang.
No, you can't, There is not a base type of a Gerneric Type. If you want to get a specific generic type by type parameters, You can use MakeGenericType. For example:
//get Func<int, string> type
typeof(Func<>).MakeGenericType(typeof(int), typeof(string));
If you want to get a Generic Type from specified generic type, You can use GetGenericTypeDefinition. For example:
//get Func<,> type
typeof(Func<int, string>).GetGenericTypeDefinition();
It is Because Func< A, B > does not inherit from Func<> It is a generic based on Func<,>.
However, you will notice that
typeof(Func<int, int>).FullName // equals "System.Func`2...
typeof(Func<int, int, int>).FullName // equals "System.Func`3...
It is a bit ugly but you could use something like
YourType.FullName.StartsWith("System.Func")
Hope it helps
Edit:
Why not use YourType.GetGenericTypeDefinition()?
Because typeof(Func<int, int>).GetGenericTypeDefinition() returns Func<,>
and typeof(Func<int, int, int>).GetGenericTypeDefinition() return Func<,,>.
Func<,> and Func<,,> are not the same Type.
This question already has answers here:
Why covariance and contravariance do not support value type
(4 answers)
Closed 8 years ago.
I'm trying to figure out why this doesn't work:
public void DefaultAction( object obj = null ){}
public void Start()
{
SomeReferenceType obj;
DefaultAction( obj ); //works
int i;
string s;
DefaultAction( i ); //works
DefaultAction( s ); //works
}
//however...
public event Action OnNullAction = DefaultAction; //works
public event Action<SomeReferenceType> OnObjectAction = DefaultAction; //works
public event Action<int> OnIntAction = DefaultAction; //doesn't work!!
Trying to bind a void(object) to an Action<ValueType> throws a parameter mismatch error, even though you can call the function directly with an int/string/bool what have you. Is there some mysterious boxing/unboxing happening? And regardless, is it possible to create a delegate that can respond to any Action<T>?
You have discovered that delegate contravariance requires reference types.
That's pretty highfalutin, I know.
First off, let me clearly state what covariance and contravariance are. Suppose you have a relationship between types: "A value of type Giraffe can be assigned to a variable of type Animal". Let's notate that as
Animal <-- Giraffe
A generic type C<T> is said to be covariant in T if replacing every type with C<that type> preserves the direction of the arrow.
IEnumerable<Animal> <-- IEnumerable<Giraffe>
Since C# 4.0, when I added this feature to the language, ou can use a sequence of giraffes anywhere you need a sequence of animals.
A generic type C<T> is said to be contravariant in T if the replacement reverses the direction of the arrow:
Action<Animal> --> Action<Giraffe>
If you need an action that requires that you give it a Giraffe and you have an action that can take any Animal, then you're all set; you need something that can take a Giraffe and an Action<Animal> can take a Giraffe. But this is not covariant. If you have an Action<Giraffe> in hand and you need an Action<Animal>, you can't use the Action<Giraffe> because *you can pass a Tiger to an Action<Animal> but not an Action<Giraffe>.
What about Func<T>? It is covariant in T. If you need a function that returns an Animal and you have a function that returns a Giraffe, you're good, because the Giraffe will be an Animal.
What about Func<A, R>? It is contravariant in A and covariant in R. It should be clear why.
So now that we know what covariance and contravariance of generic types are, what are the rules in C#? The rules are:
The type declarations must be annotated with in (contravariant) and out (covariant). For example, delegate R Func<in A, out R>(A a). Notice that the in is the thing that goes into the function and the out is the thing that comes out of the function; we named them in and out on purpose.
The compiler has to be able to prove that the annotations are safe. See the spec or my blog for details.
Variance is only supported on generic delegates and interfaces, not on generic structs, enums or classes.
The varying types have to both be reference types.
So now we come to your question. Why do they have to both be reference types? You deduced the answer: where is the boxing instruction?
Action<object> oa = (object x)=>whatever;
Action<int> ia = oa; // Suppose this works.
ia(123);
Where is the boxing instruction? Not in the body of the lambda assigned to oa -- that thing takes an object already. Not in the call to ia(123) -- that thing takes an integer. The only possible solution is that oa and ia be unequal; that this be a shorthand for
Action<object> oa = (object x)=>{whatever};
Action<int> ia = (int x)=>{ oa(x); };
But if that's what you meant to say, then just say that. People expect that a reference conversion will maintain referential identity, so C# outlaws covariant or contravariant conversions that would have to box or unbox a value.
If you have more questions on this, search my old blog (blogs.msdn.com/ericlippert) for covariance or search for the C# covariance FAQ.
Just make it generic
public void DefaultAction<T>(T param) { }
I've done a bit of google on this and have not found anything to explain the syntax..
So I'm using Action<T> for a producer consumer where Action<T> is the consumer action to perform. I right clicked on Action<T> - 'go to definition' to see its definition and this is what I was shown
public delegate void Action<in T>(T obj);
Hmmm... I've been using generics for quite a while now and have not ever used nor seen the syntax of <in T>
Anyone got a nice summation to hand to explain the syntax and what it produces?
Thanks. D
The in and out variance modifiers for generic types has been introduced in C# 4.0 to allow co and contra variance to generic types.
For generic type parameters, the in keyword specifies that the type parameter is contravariant.
For generic type parameters, the out keyword specifies that the type parameter is covariant.
And from Variance in Generic Interfaces (C# and Visual Basic) on MSDN:
Covariance permits a method to have a more derived return type than that defined by the generic type parameter of the interface.
Contravariance permits a method to have argument types that are less derived than that specified by the generic parameter of the interface.