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
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<B> 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!
}
}
A new() constructor constraint
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>();
}
}
A type parameter can be used as a constraint
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) {
}
}
Combination of Overriding Generic Methods
/*
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
*/
constructor constraint
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");
}
}
Default Constructor Constraint
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");
}
}
Demonstrate a reference constraint
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>();
}
}
Demonstrate a value type constraint
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());
}
}
Derivation Constraint
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 {
}
Reference Type Constraint
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{
}
Reference Type Constraint: A reference type constraint restricts a type parameter to a reference type.
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 {
}
There are five types of constraints:
/*
*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.
*/
Use an interface constraint
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>();
}
}