Csharp/C Sharp/Generics/Generic Constraint
Содержание
- 1 A base class constraint
- 2 A new() constructor constraint
- 3 A type parameter can be used as a constraint
- 4 Combination of Overriding Generic Methods
- 5 constructor constraint
- 6 Default Constructor Constraint
- 7 Demonstrate a reference constraint
- 8 Demonstrate a value type constraint
- 9 Derivation Constraint
- 10 Reference Type Constraint
- 11 Reference Type Constraint: A reference type constraint restricts a type parameter to a reference type.
- 12 There are five types of constraints:
- 13 Use an interface constraint
A base class constraint
<source lang="csharp"> using System; class MyBase {
public void hello() { Console.WriteLine("Hello"); }
} class B : MyBase { } class C { } class Test<T> where T : MyBase {
T obj; public Test(T o) { obj = o; } public void sayHello() { obj.hello(); }
} class BaseClassConstraintDemo {
public static void Main() { MyBase a = new MyBase(); B b = new B(); C c = new C(); Test<MyBase> t1 = new Test<MyBase>(a); t1.sayHello(); Test t2 = new Test<B>(b); t2.sayHello(); // The following is invalid because // C does not inherit MyBase. // Test<C> t3 = new Test<C>(c); // Error! }
}
</source>
A new() constructor constraint
<source lang="csharp"> using System; class MyClass {
public MyClass() { }
} class Test<T> where T : new() {
T obj; public Test() { // This works because of the new() constraint. obj = new T(); // create a T object }
} class ConsConstraintDemo {
public static void Main() { Test<MyClass> x = new Test<MyClass>(); }
}
</source>
A type parameter can be used as a constraint
<source lang="csharp">
using System; using System.Collections; public class Test{ public static void Main(){ X<Y, Z> obj=new X<Y, Z>(); } } public class Z { public void MethodA() { Console.WriteLine("Y::MethodA"); } } public class Y: Z { } public class X<T1, T2> where T1:T2 { public void MethodB(T1 arg) { } } </source>
Combination of Overriding Generic Methods
<source lang="csharp"> /* Base Method Derived Method Comments Nongeneric Generic (open) Permitted Nongeneric Generic (closed) Permitted Generic (open) Nongeneric Not permitted Generic (open) Generic (open) Permitted; must use the same type parameters Generic (open) Generic (closed) Not permitted Generic (closed) Nongeneric Permitted Generic (closed) Generic (closed) Permitted Generic (closed) Generic (open) Not permitted
- /
</source>
constructor constraint
<source lang="csharp"> using System;
public class Starter {
public static void Main() { MyClass obj = new MyClass(); obj.MethodA<XClass>(); }
} public class MyClass {
public void MethodA<T>() where T : XClass, new() { Console.WriteLine("MyClass.MethodA"); T obj = new T(); obj.MethodB(); }
} public class XClass {
public void MethodB() { Console.WriteLine("XClass.MethodB"); }
}
</source>
Default Constructor Constraint
<source lang="csharp">
using System; public class Test{ public static void Main(){ Z obj=new Z(); obj.MethodA<X>(); } } public class Z { public void MethodA<T>() where T:X, new() { Console.WriteLine("Z.MethodA"); T obj=new T(); obj.MethodB(); } } public class X{ public void MethodB() { Console.WriteLine("X.MethodB"); } }
</source>
Demonstrate a reference constraint
<source lang="csharp"> using System; class MyClass { } class Test<T> where T : class {
T obj; public Test() { // The following statement is legal only // because T is guaranteed to be a reference // type, which can be assigned the value null. obj = null; } public void print(){ Console.WriteLine(obj); }
} class ClassConstraintDemo {
public static void Main() { Test<MyClass> x = new Test<MyClass>(); // The next line is in error because int is // a value type.
// Test<int> y = new Test<int>();
}
}
</source>
Demonstrate a value type constraint
<source lang="csharp"> using System; struct MyStruct { } class MyClass { } class Test<T> where T : struct {
T obj; public Test(T x) { obj = x; }
} class Test {
public static void Main() { Test<MyStruct> x = new Test<MyStruct>(new MyStruct()); Test<int> y = new Test<int>(10); // But, the following declaration is illegal!
// Test<MyClass> z = new Test<MyClass>(new MyClass());
}
}
</source>
Derivation Constraint
<source lang="csharp"> using System; public class Starter {
public static void Main() { // good MyClass<XClass, YClass> obj = new MyClass<XClass, YClass>(); // good MyClass<XClass, WClass> obj2 = new MyClass<XClass, WClass>(); // bad MyClass<WClass, YClass> obj3 = new MyClass<WClass, YClass>(); }
} public class MyClass<K, V>
where K : XClass where V : YClass {
} public class XClass { } public class YClass { } public class WClass : YClass { }
</source>
Reference Type Constraint
<source lang="csharp">
using System; using System.Collections; public class Test{ public static void Main(){ Z<X> obj2=new Z<X>(); } } public class Z<T> where T: class { public void Iterate(T data) { } } public class X{ }
</source>
Reference Type Constraint: A reference type constraint restricts a type parameter to a reference type.
<source lang="csharp"> using System; using System.Collections;
public class Starter {
public static void Main() { // MyClass<int> obj1=new MyClass<int>(); [illegal] MyClass<XClass> obj2 = new MyClass<XClass>(); }
} public class MyClass<T> where T : class {
public void Iterate(T data) { }
} public class XClass { }
</source>
There are five types of constraints:
<source lang="csharp"> /*
*Derivation constraints state the ascendancy of a type parameter. *Interface constraints are interfaces that are implemented by the type parameter. *Value type constraints restrict a type parameter to a value type. *Reference type constraints restrict a type parameter to a reference type. *Constructor constraints stipulate that the type parameter has a default or parameterless constructor.
- /
</source>
Use an interface constraint
<source lang="csharp"> using System; class NotFoundException : ApplicationException { } public interface IPhoneNumber {
string Number { get; set; } string Name { get; set; }
} class Friend : IPhoneNumber {
string name; string number; public Friend(string n, string num) { name = n; number = num; } public string Number { get { return number; } set { number = value; } } public string Name { get { return name; } set { name = value; } }
} class Supplier : IPhoneNumber {
string name; string number; public Supplier(string n, string num) { name = n; number = num; } public string Number { get { return number; } set { number = value; } } public string Name { get { return name; } set { name = value; } }
} class EmailFriend { } class PhoneList<T> where T : IPhoneNumber {
T[] phList; int end; public PhoneList() { phList = new T[10]; end = 0; } public bool add(T newEntry) { if(end == 10) return false; phList[end] = newEntry; end++; return true; } public T findByName(string name) { for(int i=0; i<end; i++) { if(phList[i].Name == name) return phList[i]; } throw new NotFoundException(); } public T findByNumber(string number) { for(int i=0; i<end; i++) { if(phList[i].Number == number) return phList[i]; } throw new NotFoundException(); }
} class Test {
public static void Main() { PhoneList<Friend> plist = new PhoneList<Friend>(); plist.add(new Friend("A", "555-1111")); plist.add(new Friend("B", "555-6666")); plist.add(new Friend("C", "555-9999")); try { Friend frnd = plist.findByName("B"); Console.Write(frnd.Name + ": " + frnd.Number); } catch(NotFoundException) { Console.WriteLine("Not Found"); } Console.WriteLine(); PhoneList<Supplier> plist2 = new PhoneList<Supplier>(); plist2.add(new Supplier("D", "555-4444")); plist2.add(new Supplier("E", "555-3333")); plist2.add(new Supplier("F", "555-2222")); try { Supplier sp = plist2.findByNumber("555-2222"); Console.WriteLine(sp.Name + ": " + sp.Number); } catch(NotFoundException) { Console.WriteLine("Not Found"); } //PhoneList<EmailFriend> plist3 = new PhoneList<EmailFriend>(); }
}
</source>