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
Swift - Checking Unmanaged Address Book Single Value Property for Nil
Swift 3 JSON Nsfastenumerationiterator Has No Subscript Members
How to Handle "Cfnetwork Sslhandshake Failed" in iOS
How to Get a Swift Type Name as a String with Its Namespace (Or Framework Name)
Custom Back Indicator Image and iOS 11
iOS Timed Background Processing
How to Only Disable Scroll in Scrollview But Not Content View
iOS - Is Motion Activity Enabled in Settings > Privacy > Motion Activity
Uilabel with Two Different Color Text
Nsurlsessiondatatask Datataskwithurl Completion Handler Not Getting Called
Fix Cordova Geolocation Ask for Location Message
How to Access an Xcassets Directory on the Filesystem
Thread Error in Ibaction While Overriding Prepareforsegue Function
Order Two Nsmutablearrays Based on One
Ios11 Arkit: Can Arkit Also Capture the Texture of the User's Face
Asset Catalog: Access Images with Same Name in Different Folders