Generic Constraints, Where T:Struct and Where T:Class

Generic constraints, where T : struct and where T : class

Constraints are not part of the signature, but parameters are. And constraints in parameters are enforced during overload resolution.

So let's put the constraint in a parameter. It's ugly, but it works.

class RequireStruct<T> where T : struct { }
class RequireClass<T> where T : class { }

static void Foo<T>(T a, RequireStruct<T> ignore = null) where T : struct { } // 1
static void Foo<T>(T? a) where T : struct { } // 2
static void Foo<T>(T a, RequireClass<T> ignore = null) where T : class { } // 3

(better six years late than never?)

Struct and string generic constraint on class level

No, it's not possible. The best approach is to use an abstract generic base class and specialize for string and struct.

public abstract class AutoEncryptorBase<T>
{
protected T _value;
}

public class AutoEncryptor<T> : AutoEncryptorBase<T?> where T : struct
{
}

public class TextAutoEncryptor : AutoEncryptorBase<string>
{
}

Generic constraints to a specific class, why?

Perhaps this simple example might help.

If I have these classes:

public class ListOfCars<T> : List<T> where T : Car { }

public abstract class Car { }
public class Porsche : Car { }
public class Bmw : Car { }

...and then if I write this code:

var porsches = new ListOfCars<Porsche>();

// OK
porsches.Add(new Porsche());

//Error - Can't add BMW's to Porsche List
porsches.Add(new Bmw());

You can see that I can't add a BMW to a Porsche list, but if I just programmed off of the base class it would be allowed.

C# generic constraint: Array of Structs

You don't need to.

Just constrain it to : struct, then write T[] instead of T when using the type parameter.

public class DeepCopyArrayOfValueTypes<T> : IDeepCopyable<T[]>
where T : struct
{
public T[] DeepCopy(T[] t) {...}
}

Combining struct and new() generic type constraints

For struct new doesn't make sense. For classes it does.

In your case it is a redundant.

public T FactoryCreateInstance<T>() where T : new()
{
return new T();
}

It make sense to specify new constraint in a case like above but not when it is already constrained to be struct.

Parameter less constructor for value types is a C# restriction and not a CLI restriction. Maybe this is why is it specified redundantly to leave some wiggle room for future.

generic function that can return T? or T depending on whether T is struct or class

No. Neither the return type nor generic constraints are part of the method signature for binding purposes, so there is no way to disambiguate those methods at compile-time.

You could use dummy input parameters like the marked duplicate answer does to disambiguate them:

public T Get<T>(RequireClass<T> ignore = null) where T : class 

public T? Get<T>(RequireStruct<T> ignore = null) where T : struct

public class RequireStruct<T> where T : struct { }
public class RequireClass<T> where T : class { }

What does where T : class, new() mean?

That is a constraint on the generic parameter T. It must be a class (reference type) and must have a public parameter-less default constructor.

That means T can't be an int, float, double, DateTime or any other struct (value type).

It could be a string, or any other custom reference type, as long as it has a default or parameter-less constructor.

C# Generics: Constraining T where T : Object doesn't compile; Error: Constraint cannot be special class 'object'

There is no difference between the two constraints, except for that one is disallowed for being useless to explicitly state.

The C# 4.0 language specification (10.1.5 Type parameter constraints) says two things about this:

The type must not be object. Because all types derive from object,
such a constraint would have no effect if it were permitted.

...

If T has no primary constraints or type parameter constraints, its
effective base class is object.

In your comment, you said that you were trying to make T be of type Void. Void is a special type that indicates that there is no return type and cannot be used in place of T, which requires an appropriate concrete type. You will have to create a void version of your method and a T version if you want both.



Related Topics



Leave a reply



Submit