How to Make Generics in Collection Type Constraint

Generic constrain for Lists and Collections

Why don't:

public int GetCount<T>(ICollection<T> collection)
{
return collection.Count;
}

How to make a Generic Collection with Type Constraint that implement two interfaces?

You can do it like this:

interface IEmployee { void DisplayInfo(); }
interface ISalaried { void CalculateSalary(); }
interface ISalariedEmployee : IEmployee, ISalaried {}
class Doctor : ISalariedEmployee { whatever }
class Nurse : ISalariedEmployee { whatever }
...
var list = new List<ISalariedEmployee>() { new Nurse(), new Doctor() };

Does that help?

Essentially the feature you really want does not exist. There is a way to say "this generic type parameter must be constructed with a type argument that implements these two interfaces" but there is, oddly enough, not a way to say "this local variable must be initialized with a reference to an object that implements these two interfaces". It is simply a shortcoming of the C# type system that you can represent that in type parameters but not in locals. What you want is:

var list = new List<IEmployee + ISalary>();

And now you can only put things into the list that implement both interfaces. But there is no such feature in C#, unfortunately. Sorry!

Possible to have generic constraints in Arrays?

Yes and no.

In this case:

type SpecialArray<T extends DataKeys = DataKeys> = [T, Data[T]]
const arr1: SpecialArray = ['FOO', 'wrong'] // no error

You omitted the generic parameter, so the default is used. And since the default type DataKeys is all keys then the resulting value type is number | string.

However, all generic parameters must have a type assigned to them, so it doesn't work if you only remove the default:

type SpecialArray<T extends DataKeys> = [T, Data[T]]
const arr1: SpecialArray = ['FOO', 'wrong'] // error
// Generic type 'SpecialArray' requires 1 type argument(s).(2314)

It does work if you specify the generic parameter:

// errors as expected
const arr1: SpecialArray<'FOO'> = ['FOO', 'wrong'] // 2nd argument should be `number`
const arr2: SpecialArray<'BAR'> = ['BAR', 666] // 2nd argument should be `string`

But that's not exactly pretty.

Sadly, you just can't infer a generic parameter from a simple assignment in typescript.

The typical workaround for this is to use a function to make the objects for you. Since, as you note functions handle this better.

function makeSpecialArray<
T extends DataKeys
>(key: T, value: Data[T]): SpecialArray<T> {
return [key, value]
}

// these are type errors, and the objects they create are SpecialArray<SomeKey>
const arr1 = makeSpecialArray('FOO', 'wrong') // 2nd argument should be `number`
const arr2 = makeSpecialArray('BAR', 666) // 2nd argument should be `string`

Playground

C# collections type constrained generics

I think your issue here is related to the desired co-variance of the relationship between the inheritance hierarchy of the generic 3rd-party SomeBindingList<T> class and the hierarchy of the types used as parameters.

First, let me give you code that will compile:

public interface ISomeBindingList<out T>
{
}

public abstract class ParentClass
{
public abstract ISomeBindingList<ParentClass> parentList();
}

public class ChildClass : ParentClass
{
private ISomeBindingList<ChildClass> myList;

public ChildClass()
{
// this could load from/bind to a database
// myList = new SomeBindingList<ChildClass>(); // <-- we need to figure out this
}

public override ISomeBindingList<ParentClass> parentList()
{
return myList;
}
}

C# does not provide generic type co-variance for classes. But it does for interfaces. You will have to think outside the box and implement a trivial adapter for your 3rd-party SomeBindingList<T>, which implements only the lifted members that are co-variantly compatible, that is: those members where T only occurs as output.

For example, assuming SomeBindingList<T> contains a method T Get(), you would lift this member to an adapter interface, and create a trivial adapter implementation.

This would be the complete code:

public interface ISomeBindingList<out T>
{
T Get();
}

public class SomeBindingListAdapter<T> : SomeBindingList<T>, ISomeBindingList<T>
{
}

public abstract class ParentClass
{
public abstract ISomeBindingList<ParentClass> parentList();
}

public class ChildClass : ParentClass
{
private ISomeBindingList<ChildClass> myList;

public ChildClass()
{
// this could load from/bind to a database
myList = new SomeBindingListAdapter<ChildClass>();
}

public override ISomeBindingList<ParentClass> parentList()
{
return myList;
}
}

How to set constraints on generic types in Java?

Read also the discussion here: Generics and sorting in Java

Short answer, the best you can get is:

class ListObject<T extends Comparable<? super T>> {
...
}

But there is also reason to just use:

class ListObject<T extends Comparable> {
...
}

Multiple type constraint in Generic Collection instance

You cannot. But you can create an abstract class that both inherits UserControl and implements IEscpecialOptions and then constraint the generic parameter to be of the abstract type.

is this possible: c# collection of Type with constrains, or collection of generic type?

In this particular scenario, where it seems we have a "factory" pattern, we would constrain the method invoking the activator, such as

private readonly List<Type> _supportedTypes = new List<Type> ();
public void RegisterSupportedType<T> () where T : SomeConstraintType
{
_supportedTypes.Add (typeof (T));
}

// if we do not know the type, but somehow know an index to type
public object Create (int supportedTypeIndex)
{
object untyped = Activator.
CreateInstance (_supportedTypes[supportedTypeIndex]);
return untyped;
}

// if we know instance type\subtype (eg interface) and know an index
public T Create<T> (int supportedTypeIndex)
{
T typed = default (T);
object untyped = Create (supportedTypeIndex);
if (!(untyped is T))
{
// throw meaningful exception :)
}
typed = (T)(untyped);
return typed;
}

An alternative, is to create a constrained Type

public class ConstrainedType<T> 
{
public Type Type { get; private set; }
public ConstrainedType (Type type)
{
// may have this backward, would have to fact check before
// rolling out to prod ;)
if (!typeof (T).IsAssignableFrom (type))
{
// throw meaningful exception!
}
Type = type;
}
}

List<ConstrainedType<SomeTypeConstraint>> list =
new List<ConstrainedType<SomeTypeConstraint>> ();

// will throw meaningful exception if MyClass is not
// SomeTypeConstraint or a sub class
list.Add (new ConstrainedType (typeof (MyClass)));

SomeTypeConstraint baseType =
(SomeTypeConstraint)(Activator.CreateInstance(list[0].Type));


Related Topics



Leave a reply



Submit