Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
CSharpNotesForProfessionals.pdf
Скачиваний:
57
Добавлен:
20.05.2023
Размер:
6.12 Mб
Скачать

}

but classes and structures may not

class BadClass<in T1, out T2>

// not allowed

{

 

}

 

struct BadStruct<in T1, out T2>

// not allowed

{

 

}

 

 

 

nor do generic method declarations

class MyClass

{

public T Bad<out T, in T1>(T1 t1) // not allowed

{

// ...

}

}

The example below shows multiple variance declarations on the same interface

interface IFoo<in T1, out T2, T3>

//T1 : Contravariant type

//T2 : Covariant type

//T3 : Invariant type

{

// ...

}

IFoo<Animal, Dog, int> foo1 = /* ... */; IFoo<Dog, Animal, int> foo2 = foo1;

// IFoo<Animal, Dog, int> is a subtype of IFoo<Dog, Animal, int>

Section 59.12: Variant delegates

Delegates may have variant type parameters.

delegate void Action<in T>(T t);

// T is an input

delegate T Func<out

T>();

//

T is an output

delegate T2 Func<in

T1, out T2>();

//

T1 is an input, T2 is an output

 

 

 

 

This follows from the Liskov Substitution Principle, which states (among other things) that a method D can be considered more derived than a method B if:

D has an equal or more derived return type than B

D has equal or more general corresponding parameter types than B

Therefore the following assignments are all type safe:

Func<object, string> original = SomeMethod;

Func<object, object> d1 = original;

Func<string, string> d2 = original;

Func<string, object> d3 = original;

GoalKicker.com – C# Notes for Professionals

313

Section 59.13: Variant types as parameters and return values

If a covariant type appears as an output, the containing type is covariant. Producing a producer of Ts is like producing Ts.

interface IReturnCovariant<out T>

{

IEnumerable<T> GetTs();

}

If a contravariant type appears as an output, the containing type is contravariant. Producing a consumer of Ts is like consuming Ts.

interface IReturnContravariant<in T>

{

IComparer<T> GetTComparer();

}

If a covariant type appears as an input, the containing type is contravariant. Consuming a producer of Ts is like consuming Ts.

interface IAcceptCovariant<in T>

{

void ProcessTs(IEnumerable<T> ts);

}

If a contravariant type appears as an input, the containing type is covariant. Consuming a consumer of Ts is like producing Ts.

interface IAcceptContravariant<out T>

{

void CompareTs(IComparer<T> tComparer);

}

Section 59.14: Type Parameters (Interfaces)

Declaration:

interface IMyGenericInterface<T1, T2, T3, ...> { ... }

Usage (in inheritance):

class ClassA<T1, T2, T3> : IMyGenericInterface<T1, T2, T3> { ... } class ClassB<T1, T2> : IMyGenericInterface<T1, T2, int> { ... } class ClassC<T1> : IMyGenericInterface<T1, char, int> { ... } class ClassD : IMyGenericInterface<bool, char, int> { ... }

Usage (as the type of a parameter):

void SomeMethod(IMyGenericInterface<int, char, bool> arg) { ... }

GoalKicker.com – C# Notes for Professionals

314

Section 59.15: Type constraints (class and struct)

It is possible to specify whether or not the type argument should be a reference type or a value type by using the respective constraints class or struct. If these constraints are used, they must be defined before all other constraints (for example a parent type or new()) can be listed.

//TRef must be a reference type, the use of Int32, Single, etc. is invalid.

//Interfaces are valid, as they are reference types

class AcceptsRefType<TRef> where TRef : class

{

//TStruct must be a value type. public void AcceptStruct<TStruct>()

where TStruct : struct

{

}

//If multiple constraints are used along with class/struct

//then the class or struct constraint MUST be specified first public void Foo<TComparableClass>()

where TComparableClass : class, IComparable

{

}

}

Section 59.16: Explicit type parameters

There are di erent cases where you must Explicitly specify the type parameters for a generic method. In both of the below cases, the compiler is not able to infer all of the type parameters from the specified method parameters.

One case is when there are no parameters:

public void SomeMethod<T, V>()

{

// No code for simplicity

}

SomeMethod(); // doesn't compile

SomeMethod<int, bool>(); // compiles

Second case is when one (or more) of the type parameters is not part of the method parameters:

public K SomeMethod<K, V>(V input)

{

return default(K);

}

int num1 = SomeMethod(3); // doesn't compile

int num2 = SomeMethod<int>("3"); // doesn't compile int num3 = SomeMethod<int, string>("3"); // compiles.

Section 59.17: Type Parameters (Classes)

Declaration:

class MyGenericClass<T1, T2, T3, ...>

{

GoalKicker.com – C# Notes for Professionals

315

// Do something with the type parameters.

}

Initialisation:

var x = new MyGenericClass<int, char, bool>();

Usage (as the type of a parameter):

void AnotherMethod(MyGenericClass<float, byte, char> arg) { ... }

Section 59.18: Type Parameters (Methods)

Declaration:

void MyGenericMethod<T1, T2, T3>(T1 a, T2 b, T3 c)

{

// Do something with the type parameters.

}

Invocation:

There is no need to supply type arguements to a genric method, because the compiler can implicitly infer the type.

int x =10; int y =20;

string z = "test"; MyGenericMethod(x,y,z);

However, if there is an ambiguity, generic methods need to be called with type arguemnts as

MyGenericMethod<int, int, string>(x,y,z);

Section 59.19: Generic type casting

///<summary>

///Converts a data type to another data type.

///</summary>

public static class Cast

{

///<summary>

///Converts input to Type of default value or given as typeparam T

///</summary>

///<typeparam name="T">typeparam is the type in which value will be returned, it could be any type eg. int, string, bool, decimal etc.</typeparam>

///<param name="input">Input that need to be converted to specified type</param>

///<param name="defaultValue">defaultValue will be returned in case of value is null or any exception occures</param>

///<returns>Input is converted in Type of default value or given as typeparam T and returned</returns>

public static T To<T>(object input, T defaultValue)

{

var result = defaultValue;

try

{

if (input == null || input == DBNull.Value) return result; if (typeof (T).IsEnum)

GoalKicker.com – C# Notes for Professionals

316