Do you gain any operations when you constrain a generic type using where T : struct?
This may be a bit of an abstract question, so apologies in advance.
I am looking into generics in .NET, and was wondering about the where T : struct
constraint.
I understand that this allows you to restrict the type used to be a value type. My question is, without any type constraint, you can do a limited number of operations on T.
Do you gain the ability to use any additional operations when you specify where T : struct
, or is the only value in restricting the types you can pass in?
Edit
Some interesting answers so far, thanks. I guess the question I am actually asking is that if i were to write,开发者_如何转开发 (in a discussion about how to use generics),
"Now that you have constrained the type argument to value types, you can also do ___________________ on/with objects of that type"
Is there anything to put in that blank? I can think of things for the other constraints, but not this one.
All that T : struct
gains you is an implicit new()
constructor, and a few obvious things involving null
. Perhaps more importantly, callers can't use classes, interfaces or Nullable<T>
.
What types of operations are you after? For operators, try dynamic
in 4.0, or MiscUtil in 3.5
The only thing that you gain relative to other possible sets of constraints is the ability to work with values of type Nullable<T>
(which is why T: struct
prohibits caller from passing Nullable<T>
as a type parameter - it can't be nested).
No, you don't gain any operations on T
by specifying the where T: struct
generic type constraint. You constrain your callers to only specify value types (except Nullable<T>
value types, which are not allowed).
One type of operation which is guaranteed not to be available with a mutable class and may sometimes be available with a mutable struct is the ability to copy the state of a thing using the assignment operator. Using mutating interfaces with structures is tricky, since attempting to use a mutating interface on a structure in a read-only context will yield code that compiles cleanly but does not work (I really wish compilers would recognize an attribute on struct and interface members that would indicate that they should not be usable on read-only structures). Nonetheless, there are some contexts where such a thing can be useful.
For example, if an algorithm required the ability to store the state of an enumerator and revert the enumerator to its saved state, and if the enumerator was a generic type TEnum
constrained to both struct
and IEnumerator<T>, it may be possible to copy the
TEnumto a local variable of that type and then later copy it back. Note that this would work with some but not all
structtypes which implement
IEnumerable; such a technique should in practice probably only be used with interfaces that explicitly document a requirement that all legitimate struct-type implementations must exhibit value semantics (
IEnumerator` does not have such a documented requirement).
Note that the fact that code may use the ability to copy structs by value when it exists, that does preclude the possibility of a slightly-different (perhaps less-efficient) method using a class-type implementation of the interface. The function signatures:
void ActOnSequence<T>(T theEnumerator) where T:struct, IEnumerator<String>;
void ActOnSequence(IEnumerator<String> theEnumerator);
can co-exist and be used without difficulty. The former will be invoked on value-type implementations of the interface, while the latter will be invoked on heap-type implementations. Note that without the struct
constraint, it would not be possible to have both of the above methods in scope and have the correct method invoked automatically.
精彩评论