I have created INamedTypeSymbol for concrete types using GetTypeByMetadataName
INamedTypeSymbol listTypeSymbol = context.SemanticModel.Compilation.GetTypeByMetadataName("System.Collections.Generic.List`1");
INamedTypeSymbol collectionTypeSymbol = context.SemanticModel.Compilation.GetTypeByMetadataName("System.Collections.Generic.ICollection`1");
One of them is a symbol of a runtime type of List<T>, other of them is a symbol of a runtime type of ICollection<T>. The List<T> type is derived from the type of ICollection<T>.
How can I check an inheritance relation for INamedTypeSymbol?
I try to do it using a ClassifyConversion method
Conversion con = context.SemanticModel.Compilation.ClassifyConversion(listTypeSymbol, collectionTypeSymbol);
However this function returns a Explicit Reference value of conversion. I am expected to see something like the Implicit Reference value.
This is a complicated one.
GetTypeByMetadataName("System.Collections.Generic.List`1") returns an open generic type, which is in effect a type constructor that can be used to create closed generic types with specific parameters.
It doesn't make sense to speak about conversions between open generic types; two types A<> and B<> might be differently convertible if B<> is declared as B<T> : A<List<T>> or more-complex relationships.
You can only check for convertibility between closed generic types that share the same type parameter. To do that, call Construct() and pass types for the type parameters.
Related
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.
For example, if you run the following code...
Type IListType = new List<string>().GetType()
.GetInterface("IList`1")
.GetGenericTypeDefinition();
...and you watch IListType variable, you'll find that the whole Type instance has all properties available like FullName and others.
But what happens when you run the code bellow?
Type IListType2 = typeof(List<>).GetInterface("IList`1")
Now IListType got from a generic type definition isn't the same as the first code sample: most Type properties will return null.
The main issue with this is that IListType == IListType2 doesn't equal while they're the same type.
What's going on?
This is ugly...
Now see what happens if you call IListType2.GetGenericTypeDefinition()... It recovers the type information!
It would be great that a .NET Framework development team member could explain us why an already generic type definition which has strangely lost its metadata has IsGenericTypeDefinition property set to false while it's still a generic type definition, and finally, if you call GetGenericTypeDefinition() on it, you recover the type information.
This is strange...
The following equality will be true:
Type IListType = new List<string>().GetType()
.GetInterface("IList`1")
.GetGenericTypeDefinition();
// Got interface is "like a generic type definition" since it has
// no type for T generic parameter, and once you call
// GetGenericTypeDefinition() again, it recovers the lost metadata
// and the resulting generic type definition equals the one got from
// List<string>!
Type IListType2 = typeof(List<>).GetInterface("IList`1").GetGenericTypeDefinition();
bool y = IListType == IListType2;
The following types are all different and not connected by an inheritance relationship:
IList<T>
IList<int>
IList<string>
All of these have different Type objects because you can do different things with them. The latter two are the specializations of the former. The first is the generic type definition (which you can obtain through GetGenericTypeDefinition).
There is another part to the explanation. When you say class List<T> : IList<T> then the IList<T> part is not equal to typeof(IList<>) because it is already specialized to T. This is no longer a generic type definition. It is a concrete type such as IList<int>. It is specialized to bind its only type argument to the T that List<T> was specialized to.
Experiment for LINQPad:
Type bound = new List<string>().GetType().GetInterface("IList`1");
bound.GenericTypeArguments.Single().Dump(); //string
Type bound = typeof(List<>).GetInterface("IList`1");
bound.GenericTypeArguments.Single().Dump(); //"T"
(bound.GenericTypeArguments.Single() == typeof(List<>).GetGenericArguments().Single()).Dump(); //true
The first version of IList<T> is the actual typed version of IList<T>, let's say IList<string>.
The second one is the generic definition of IList<T> without a type for T.
That makes the two interfaces different. There are not the same, since the first is a concrete version of the second.
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.
I want to restrict the generic type parameter to:
1) either that of a certain user defined reference type;
OR
2) any of the primitive types in the CLR;
How do I say something to the effect of:
interface IDataManager<T>: IDataManager
where T: IDataObject, T: ValueType
There's no constraint you can use that limits you to the built-in primitives. What I would do to get around that is overload the method for each primitive, and perhaps have each overload simply pass it's argument to a private generic method that holds the common code.
From Constraint cannot be special class 'System.Enum'
More investigation shows the C# 2.0
specification to have the following
comments on constraints:
A class-type constraint must satisfy
the following rules:
The type must be a class type.
The type must not be sealed.
The type must not be one of the following types: System.Array,
System.Delegate, System.Enum, or
System.ValueType.
The type must not be object. Because all types derive from
object, such a constraint would
have no effect if it were
permitted.
At most one constraint for a given type parameter can be a class type.
Also Compiler Error CS0702
And mentioned at
Jon Skeet: Coding Blog : Generic constraints for enums and delegates
T: ValueType
The closest you can get is T : struct, but that wouldn't limit it only to CLR types. Either way, I don't believe there is a way to have an OR generic constraint. You could have one generic method and n-overloads for specific types.
You also can not, for example, define multiple generic functions differing only in their constraints. Constraints are not part of the signature. See: http://blogs.msdn.com/ericlippert/archive/2009/12/10/constraints-are-not-part-of-the-signature.aspx
I know C# has both value and reference types, but how can you do a this:
int age = 100;
string blah = age.ToString();
If age is a value type, how does it have a ToString method on it? Does it get converted to an object ONLY when required internally then?
If age is a value type, how does it
have a ToString method on it?
Value types are allowed to have methods on them. Why wouldn't they? A method "on a type" is just a hunk of code that happens to be associated with a particular type; why do you believe that it matters whether that type is classified as a "reference type" or "value type"?
That's not a rhetorical question. I am interested in learning about what intuitions people have about code, particularly when those intuitions are incorrect. By understanding what people get wrong intuitively, we can try to come up with better abstractions that are more intuitive.
Does it get converted to an object ONLY when required internally then?
What exactly do you mean by "converted to an object"? Do you mean "boxed"?
There are many situations in which a value type must be boxed. Some of them are straightforward -- like when you cast a value type to object or an interface. Some of them are obscure. (There are bizarre situations in generic methods where we must box and unbox things in ways you might not expect.)
In this particular situation there is no boxing. Calling a method directly implemented on a value type simply calls that hunk of code. There's no need to treat the thing as "object"; the hunk of code we're calling knows the type of the thing.
You want to look up boxing/unboxing.
Boxing
System.Int32 inherits System.ValueType which inherits System.Object.
All class, struct, enum, array, nullable and delegate types eventually derive from object. All interface types and type parameter types are implicitly convertible to object. And all pointer types neither derive from nor are convertible to object
All Framework objects inherit from System.Object (though it is possible to declare a type in MSIL which doesn't).
The object.ToString() method is a virtual method.
The special rule for value types which attempt to call a method from System.Object is this:
If the value type has overridden the method (as int and all numeric types do with ToString()) then the value type is not boxed ("converted" or "wrapped" to object), but the implementation method is called directly.
If the value type did not provide an implementation for such method (for example, a custom struct), the value type is boxed, and the base implemented mathod is called.
As for details about boxing/unboxing, there's plenty of information in msdn.
All types (reference and value) inherit from Object. (Although, like others have said it is possible to define one that doesn't, but not in C#, you have to do it in MSIL)
This means that any value type will still inherit methods from the base object. In order for a value type to call a method on the base Object type it must first be boxed so it can be treated as a reference type (boxing is the process of taking a value type and shoving it into a reference type shaped box so it behaves like a reference type). However in this specific case Int32 implements it's own version of ToString (as do most of the common numeric value types) which is just a normal methods on the value type itself, so it doesn't have to be boxed to call it.
Value types, can have methods and properties just like reference types. The limitations are that structs (C#'s value types) don't support inheritance (except from Object) or finalizers.
There is a good article on the differences between value and reference types here .
Comparing "Value Type" vs "Reference Type" doesn't say anything about whether the type is or is not an object. All it tells is you is the semantics of the type: things like how it's passed to functions, whether you need to use 'new' to instantiate it, and whether it's stored on the stack or the heap. Even that last one is just an implementation detail.
Perhaps more of an understanding of the OO calling convention is needed.
When an object is created, it doesn't actually copy the code for ToString, behind the scenes your object call is translated from
target.ToString ();
to something logically like:
ToString (target);
So there's only one copy of function code (per polymorphic instance) and an object pointer is passed in when a method is called.
all of the answers are mostly correct but i feel like the method belongs to system.object and system.valuetype and system.Int32 are derived from it .so when you create an instence of it it will show the methods of the base class .
Boxed value types inherit from object, but they have reference semantics rather than value semantics. Unboxed value types are not objects, but there exists an implicit representation-changing conversion between value types and Object. Interfaces types do not inherit from Object, but there exists an implicit representation-preserving conversion between variables/parameters/fields of interface type and Object. Note that an interface constraint on a generic is not make the generic type an interface type. A conversion from a generic type to either Object or an interface type will be a representation-preserving conversion if the generic type happens to be a value type, even if it implements the interfaces to whose type is is converted.