Restrict a generic type - c#

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

Related

Is covariance all about accepting values?

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.

INamedTypeSymbol inheritance relation in the Roslyn

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.

The type must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'System.Nullable<T>'

I create a generic class:
public class Pair<L, R>
{
public L? left;
public R? right;
// some code
}
I want to use there null-able variables for generic types. Compiler gives the error:
The type must be a non-nullable value type in order to use it as
parameter 'T' in the generic type or method 'System.Nullable'
What should be the correct construct in this case to overcome this error? Thank you.
You can constrain them to be value types:
public class Pair<L, R>
where L: struct
where R: struct
But that disallows reference types (classes), it's not clear if that is what you want.
When L and R are reference types you don't need the ?
Writing a generic Pair that allows both is a lot harder. I'm not sure if it can be done directly. Maybe in C# 8.
Otherwise you'll need some wrapper around the members.

How to extract generic method constraints via reflection in C#?

Given an object of type System.Reflection.MethodInfo how can I extract generic parameter constraints? Somehow I can not find reasonable information about this.
All you need to do is grab the generic method definition, and list the generic arguments on that:
method
.GetGenericMethodDefinition()
.GetGenericArguments()
.Select(i => i.GetGenericParameterConstraints())
.Dump();
However, note that this doesn't 100% correspond to C#'s generic type constrains - there's a bit of wiggle room. Still, if you only care about e.g. a base-type constraint, it will work fine :)
As an example, class isn't actually a type constraint at all, interestingly, while struct is "translated" as System.ValueType (not too surprising). new() isn't a type constraint either, so this method doesn't work to find that.
If you need to take those constraints into account as well, use the GenericParameterAttributes property in the Select. For example, struct constraint will give you NotNullableValueTypeConstraint | DefaultConstructorConstraint.
You are probably looking for Type.GetGenericParameterConstraints Method ()
Returns an array of Type objects that represent the constraints on the
current generic type parameter.
Also Type.GetGenericArguments Method ()
Returns an array of Type objects that represent the type arguments of
a closed generic type or the type parameters of a generic type
definition

How do ValueTypes derive from Object (ReferenceType) and still be ValueTypes?

C# doesn't allow structs to derive from classes, but all ValueTypes derive from Object. Where is this distinction made?
How does the CLR handle this?
C# doesn't allow structs to derive from classes
Your statement is incorrect, hence your confusion. C# does allow structs to derive from classes. All structs derive from the same class, System.ValueType, which derives from System.Object. And all enums derive from System.Enum.
UPDATE: There has been some confusion in some (now deleted) comments, which warrants clarification. I'll ask some additional questions:
Do structs derive from a base type?
Plainly yes. We can see this by reading the first page of the specification:
All C# types, including primitive types such as int and double, inherit from a single root object type.
Now, I note that the specification overstates the case here. Pointer types do not derive from object, and the derivation relationship for interface types and type parameter types is more complex than this sketch indicates. However, plainly it is the case that all struct types derive from a base type.
Are there other ways that we know that struct types derive from a base type?
Sure. A struct type can override ToString. What is it overriding, if not a virtual method of its base type? Therefore it must have a base type. That base type is a class.
May I derive a user-defined struct from a class of my choice?
Plainly no. This does not imply that structs do not derive from a class. Structs derive from a class, and thereby inherit the heritable members of that class. In fact, structs are required to derive from a specific class: Enums are required to derive from Enum, structs are required to derive from ValueType. Because these are required, the C# language forbids you from stating the derivation relationship in code.
Why forbid it?
When a relationship is required, the language designer has options: (1) require the user to type the required incantation, (2) make it optional, or (3) forbid it. Each has pros and cons, and the C# language designers have chosen differently depending on the specific details of each.
For example, const fields are required to be static, but it is forbidden to say that they are because doing so is first, pointless verbiage, and second, implies that there are non-static const fields. But overloaded operators are required to be marked as static, even though the developer has no choice; it is too easy for developers to believe that an operator overload is an instance method otherwise. This overrides the concern that a user may come to believe that the "static" implies that, say "virtual" is also a possibility.
In this case, requiring a user to say that their struct derives from ValueType seems like mere excess verbiage, and it implies that the struct could derive from another type. To eliminate both these problems, C# makes it illegal to state in the code that a struct derives from a base type, though plainly it does.
Similarly all delegate types derive from MulticastDelegate, but C# requires you to not say that.
So, now we have established that all structs in C# derive from a class.
What is the relationship between inheritance and derivation from a class?
Many people are confused by the inheritance relationship in C#. The inheritance relationship is quite straightforward: if a struct, class or delegate type D derives from a class type B then the heritable members of B are also members of D. It's as simple as that.
What does it mean with regards to inheritance when we say that a struct derives from ValueType? Simply that all the heritable members of ValueType are also members of the struct. This is how structs obtain their implementation of ToString, for example; it is inherited from the base class of the struct.
All heritable members? Surely not. Are private members heritable?
Yes. All private members of a base class are also members of the derived type. It is illegal to call those members by name of course if the call site is not in the accessibility domain of the member. Just because you have a member does not mean you can use it!
We now continue with the original answer:
How does the CLR handle this?
Extremely well. :-)
What makes a value type a value type is that its instances are copied by value. What makes a reference type a reference type is that its instances are copied by reference. You seem to have some belief that the inheritance relationship between value types and reference types is somehow special and unusual, but I don't understand what that belief is. Inheritance has nothing to do with how things are copied.
Look at it this way. Suppose I told you the following facts:
There are two kinds of boxes, red
boxes and blue boxes.
Every red box is empty.
There are three special blue boxes called O, V and E.
O is not inside any box.
V is inside O.
E is inside V.
No other blue box is inside V.
No blue box is inside E.
Every red box is in either V or E.
Every blue box other than O is itself inside a blue box.
The blue boxes are reference types, the red boxes are value types, O is System.Object, V is System.ValueType, E is System.Enum, and the "inside" relationship is "derives from".
That's a perfectly consistent and straightforward set of rules which you could easily implement yourself, if you had a lot of cardboard and a lot of patience. Whether a box is red or blue has nothing to do with what it's inside; in the real world it is perfectly possible to put a red box inside a blue box. In the CLR, it is perfectly legal to make a value type that inherits from a reference type, so long as it is either System.ValueType or System.Enum.
So let's rephrase your question:
How do ValueTypes derive from Object (ReferenceType) and still be ValueTypes?
as
How is it possible that every red box (value types) is inside (derives from) box O (System.Object), which is a blue box (a reference Type) and still be a red box (a value type)?
When you phrase it like that, I hope it's obvious. There's nothing stopping you from putting a red box inside box V, which is inside box O, which is blue. Why would there be?
AN ADDITIONAL UPDATE:
Joan's original question was about how it is possible that a value type derives from a reference type. My original answer did not really explain any of the mechanisms that the CLR uses to account for the fact that we have a derivation relationship between two things that have completely different representations -- namely, whether the referred-to data has an object header, a sync block, whether it owns its own storage for the purposes of garbage collection, and so on. These mechanisms are complicated, too complicated to explain in one answer. The rules of the CLR type system are quite a bit more complex than the somewhat simplified flavour of it that we see in C#, where there is not a strong distinction made between the boxed and unboxed versions of a type, for example. The introduction of generics also caused a great deal of additional complexity to be added to the CLR. Consult the CLI specification for details, paying particular attention to the rules for boxing and constrained virtual calls.
This is a somewhat artificial construct maintained by the CLR in order to allow all types to be treated as a System.Object.
Value types derive from System.Object through System.ValueType, which is where the special handling occurs (ie: the CLR handles boxing/unboxing, etc for any type deriving from ValueType).
Small correction, C# doesn't allow structs to custom derive from anything, not just classes. All a struct can do is implement an interface which is very different from derivation.
I think the best way to answer this is that ValueType is special. It is essentially the base class for all value types in the CLR type system. It's hard to know how to answer "how does the CLR handles this" because it's simply a rule of the CLR.
Your statement is incorrect, hence your confusion. C# does allow structs to derive from classes. All structs derive from the same class, System.ValueType
So let's try this:
struct MyStruct : System.ValueType
{
}
This will not even compile. Compiler will remind you "Type 'System.ValueType' in interface list is not an interface".
When decompile Int32 which is a struct, you will find :
public struct Int32 : IComparable, IFormattable, IConvertible
{}, not mentionning it is derived from System.ValueType. But in object browser, you do find Int32 does inherit from System.ValueType.
So all these lead me to believe:
I think the best way to answer this is that ValueType is special. It is essentially the base class for all value types in the CLR type system. It's hard to know how to answer "how does the CLR handles this" because it's simply a rule of the CLR.
A boxed value type is effectively a reference type (it walks like one and quacks like one, so effectively it is one). I would suggest that ValueType isn't really the base type of value types, but rather is the base reference type to which value types can be converted when cast to type Object. Non-boxed value types themselves are outside the object hierarchy.
Rationale
Of all the answers, #supercat's answer comes closest to the actual answer. Since the other answers don't really answer the question, and downright make incorrect claims (for example that value types inherit from anything), I decided to answer the question.
Prologue
This answer is based on my own reverse engineering and the CLI specification.
struct and class are C# keywords. As far as the CLI is concerned, all types (classes, interfaces, structs, etc.) are defined by class definitions.
For example, an object type (Known in C# as class) is defined as follows:
.class MyClass
{
}
An interface is defined by a class definition with the interface semantic attribute:
.class interface MyInterface
{
}
What about value types?
The reason that structs can inherit from System.ValueType and still be value types, is because.. they don't.
Value types are simple data structures. Value types do not inherit from anything and they cannot implement interfaces.
Value types are not subtypes of any type, and they do not have any type information. Given a memory address of a value type, it's not possible to identify what the value type represents, unlike a reference type which has type information in a hidden field.
If we imagine the following C# struct:
namespace MyNamespace
{
struct MyValueType : ICloneable
{
public int A;
public int B;
public int C;
public object Clone()
{
// body omitted
}
}
}
The following is the IL class definition of that struct:
.class MyNamespace.MyValueType extends [mscorlib]System.ValueType implements [mscorlib]System.ICloneable
{
.field public int32 A;
.field public int32 B;
.field public int32 C;
.method public final hidebysig newslot virtual instance object Clone() cil managed
{
// body omitted
}
}
So what's going on here? It clearly extends System.ValueType, which is an object/reference type, and implements System.ICloneable.
The explanation is, that when a class definition extends System.ValueType it actually defines 2 things: A value type, and the value type's corresponding boxed type.
The members of the class definition define the representation for both the value type and the corresponding boxed type.
It is not the value type that extends and implements, it's the corresponding boxed type that does. The extends and implements keywords only apply to the boxed type.
To clarify, the class definition above does 2 things:
Defines a value type with 3 fields (And one method). It does not inherit from anything, and it does not implement any interfaces (value types can do neither).
Defines an object type (the boxed type) with 3 fields (And implementing one interface method), inheriting from System.ValueType, and implementing the System.ICloneable interface.
Note also, that any class definition extending System.ValueType is also intrinsically sealed, whether the sealed keyword is specified or not.
Since value types are just simple structures, don't inherit, don't implement and don't support polymorphism, they can't be used with the rest of the type system.
To work around this, on top of the value type, the CLR also defines a corresponding reference type with the same fields, known as the boxed type.
So while a value type can't be passed around to methods taking an object, its corresponding boxed type can.
Now, if you were to define a method in C# like
public static void BlaBla(MyNamespace.MyValueType x),
you know that the method will take the value type MyNamespace.MyValueType.
Above, we learned that the class definition that results from the struct keyword in C# actually defines both a value type and an object type.
We can only refer to the defined value type, though. Even though the CLI specification states that the constraint keyword boxed can be used to refer to a boxed version of a type, this keyword doesn't exist (See ECMA-335, II.13.1 Referencing value types).
But lets imagine that it does for a moment.
When refering to types in IL, a couple of constraints are supported, among which are class and valuetype.
If we use valuetype MyNamespace.MyType we're specifying the value type class definition called MyNamespace.MyType.
Likewise, we can use class MyNamespace.MyType to specify the object type class definition called MyNamespace.MyType.
Which means that in IL you can have a value type (struct) and an object type (class) with the same name and still distinguish them.
Now, if the boxed keyword noted by the CLI specification was actually implemented, we'd be able to use boxed MyNamespace.MyType to specify the boxed type of the value type class definition called MyNamespace.MyType.
So, .method static void Print(valuetype MyNamespace.MyType test) cil managed takes the value type defined by a value type class definition named MyNamespace.MyType,
while .method static void Print(class MyNamespace.MyType test) cil managed takes the object type defined by the object type class definition named MyNamespace.MyType.
likewise if boxed was a keyword, .method static void Print(boxed MyNamespace.MyType test) cil managed would take the boxed type of the value type defined by a class definition named MyNamespace.MyType.
You'd then be able to instantiate the boxed type like any other object type and pass it around to any method that takes a System.ValueType, object or boxed MyNamespace.MyValueType as an argument,
and it would, for all intents and purposes, work like any other reference type. It is NOT a value type, but the corresponding boxed type of a value type.
Summary
So, in summary, and to answer the question:
Value types are not reference types and do not inherit from System.ValueType or any other type, and they cannot implement interfaces.
The corresponding boxed types that are also defined do inherit from System.ValueType and can implement interfaces.
A .class definition defines different things depending on circumstance.
If the interface semantic attribute is specified, the class definition defines an interface.
If the interface semantic attribute is not specified, and the definition does not extend System.ValueType, the class definition defines an object type (class).
If the interface semantic attribute is not specified, and the definition does extend System.ValueType, the class definition defines a value type and its corresponding boxed type (struct).
Memory layout
This section assumes a 32-bit process
As already mentioned, value types do not have type information, and thus it's not possible to identify what a value type represents from its memory location.
A struct describes a simple data type, and contains just the fields it defines:
public struct MyStruct
{
public int A;
public short B;
public int C;
}
If we imagine that an instance of MyStruct was allocated at address 0x1000, then this is the memory layout:
0x1000: int A;
0x1004: short B;
0x1006: 2 byte padding
0x1008: int C;
Structs default to sequential layout. Fields are aligned on boundaries of their own size. Padding is added to satisfy this.
If we define a class in the exact same way, as:
public class MyClass
{
public int A;
public short B;
public int C;
}
Imagining the same address, the memory layout is as follows:
0x1000: Pointer to object header
0x1004: int A;
0x1008: int C;
0x100C: short B;
0x100E: 2 byte padding
0x1010: 4 bytes extra
Classes default to automatic layout, and the JIT compiler will arrange them in the most optimal order. Fields are aligned on boundaries of their own size. Padding is added to satisfy this.
I'm not sure why, but every class always has an additional 4 bytes at the end.
Offset 0 contains the address of the object header, which contains type information, the virtual method table, etc.
This allows the runtime to identify what the data at an address represents, unlike value types.
Thus, value types do not support inheritance, interfaces nor polymorphism.
Methods
Value types do not have virtual method tables, and thus do not support polymorphism.
However, their corresponding boxed type does.
When you have an instance of a struct and attempt to call a virtual method like ToString() defined on System.Object, the runtime has to box the struct.
MyStruct myStruct = new MyStruct();
Console.WriteLine(myStruct.ToString()); // ToString() call causes boxing of MyStruct.
However, if the struct overrides ToString() then the call will be statically bound and the runtime will call MyStruct.ToString() without boxing and without looking in any virtual method tables (structs don't have any).
For this reason, it's also able to inline the ToString() call.
If the struct overrides ToString() and is boxed, then the call will be resolved using the virtual method table.
System.ValueType myStruct = new MyStruct(); // Creates a new instance of the boxed type of MyStruct.
Console.WriteLine(myStruct.ToString()); // ToString() is now called through the virtual method table.
However, remember that ToString() is defined in the struct, and thus operates on the struct value, so it expects a value type. The boxed type, like any other class, has an object header. If the ToString() method defined on the struct was called directly with the boxed type in the this pointer, when trying to access field A in MyStruct, it would access offset 0, which in the boxed type would be the object header pointer.
So the boxed type has a hidden method that does the actual overriding of ToString(). This hidden method unboxes (address calculation only, like the unbox IL instruction) the boxed type then statically calls the ToString() defined on the struct.
Likewise, the boxed type has a hidden method for each implemented interface method that does the same unboxing then statically calls the method defined in the struct.
CLI specification
Boxing
I.8.2.4
For every value type, the CTS defines a corresponding reference type called the boxed type. The reverse is not true: In general, reference types do not have a corresponding value type. The representation of a value of a boxed type (a boxed value) is a location where a value of the value type can be stored. A boxed type is an object type and a boxed value is an object.
Defining value types
I.8.9.7
Not all types defined by a class definition are object types (see §I.8.2.3); in particular, value types are not object types, but they are defined using a class definition. A class definition for a value type defines both the (unboxed) value type and the associated boxed type (see §I.8.2.4). The members of the class definition define the representation of both.
II.10.1.3
The type semantic attributes specify whether an interface, class, or value type shall be defined. The interface attribute specifies an interface. If this attribute is not present and the definition extends (directly or indirectly) System.ValueType, and the definition is not for System.Enum, a value type shall be defined (§II.13). Otherwise, a class shall be defined (§II.11).
Value types do not inherit
I.8.9.10
In their unboxed form value types do not inherit from any type. Boxed value types shall inherit directly from System.ValueType unless they are enumerations, in which case, they shall inherit from System.Enum. Boxed value types shall be sealed.
II.13
Unboxed value types are not considered subtypes of another type and it is not valid to use the isinst instruction (see Partition III) on unboxed value types. The isinst instruction can be used for boxed value types, however.
I.8.9.10
A value type does not inherit; rather the base type specified in the class definition defines the base type of the boxed type.
Value types do not implement interfaces
I.8.9.7
Value types do not support interface contracts, but their associated boxed types do.
II.13
Value types shall implement zero or more interfaces, but this has meaning only in their boxed form (§II.13.3).
I.8.2.4
Interfaces and inheritance are defined only on reference types. Thus, while a value type definition (§I.8.9.7) can specify both interfaces that shall be implemented by the value type and the class (System.ValueType or System.Enum) from which it inherits, these apply only to boxed values.
The non-existent boxed keyword
II.13.1
The unboxed form of a value type shall be referred to by using the valuetype keyword followed by a type reference. The boxed form of a value type shall be referred to by using the boxed keyword followed by a type reference.
Note: The specification is wrong here, there is no boxed keyword.
Epilogue
I think part of the confusion of how value types seem to inherit, stems from the fact that C# uses casting syntax to perform boxing and unboxing, which makes it seem like you're performing casts, which is not really the case (although, the CLR will throw an InvalidCastException if attempting to unbox the wrong type).
(object)myStruct in C# creates a new instance of the boxed type of the value type; it does not perform any casts.
Likewise, (MyStruct)obj in C# unboxes a boxed type, copying the value part out; it does not perform any casts.

Categories

Resources