Принципы объектно-ориентированного программирования

         

Запрос о реализации интерфейса с помощью as



Запрос о реализации интерфейса с помощью as

Приглядевшись к MSIL-коду, сгенерированному из предыдущего примера IsOperator2App (см. MSIL-код после этого абзаца), вы заметите проблему, связанную с оператором is. Сразу после выделения объекта и подготовки стека вызывается isinst. Код операции isinst, генерируемый компилятором для оператора С# is, проверяет, чем является объект: экземпляром класса или интерфейсом. Заметьте, что лишь через несколько строк, при условии, что проверка условий пройдена, компилятор генерирует код операции castclass. Этот код выполняет собственную проверку, и, поскольку он работает несколько иначе, чем


isinst, в результате сгенерированный IL-код выполняет неэффективную работу, дважды проверяя правильность приведения.

.method public hidebysig static void MainQ il managed {

.entrypoint

// Code size 72 (0x48)

.maxstack 4

.locals (class MyControl V_0,

class ISerializable V_1, bool V_2)

IL_0000: newobj instance void MyControl::.ctor()

IL_0005: stloc.O

IL_0006: ldloc.0

ILJ)007: isinst ISerializable

IL_OOOc: brfalse.s IL_003d

IL_OOOe: ldloc.0

IL_OOOf: castclass ISerializable

IL_0014: stloc.1

IL_0015: ldloc.1

IL_0016: callvirt instance bool ISerializable::Save()

IL_001b: stloc.2

IL_001c: Idstr "The saving of '{0}' was {1}successful"

IL_0021: ldloc.0

IL_0022: call instance class System.String FancyControl::get_data()

IL_0027: ldloc.2

IL_0028: brtrue.s IL_0031

IL_002a: Idstr "not "

IL_002f: br.s IL_0036

IL_0031: Idstr

IL_0036: call void [mscorlib]System.Console::WriteLLne(class System. String,

class System.Object,

class System.Object) IL_003b: br.s IL_0047

IL_003d: Idstr "The ISerializable interface is not implemented." IL_0042: call void [mscorlib]System.Console::WriteLine(class System. String) IL_0047: ret } // end of method IsOperator2App::Hain

Мы можем повысить эффективность процесса проверки с помощью оператора as, который преобразует совместимые типы и принимает такой вид:

объект = выражение as тип

где выражение — любой ссылочный тип

Можно думать, что оператор as представляет собой комбинацию оператора is и, если рассматриваемые типы совместимы, приведения. Важное различие между as и is в том, что если выражение и тип несовместимы, то вместо возврата булевского значения оператор as устанавливает объект в null. Теперь наш пример можно переписать:

using System;

public class FancyControl {

protected string Data; public string data {

get {

return this.Data; }

set {

this.Data = value; > } }

interface ISerializable {

bool Save(); >

interface IValidate {

bool ValidateQ; }

class HyControl : FancyControl, IValidate

{

public MyControlO

{

data = "my grid data";

}

public bool ValidateO

{

Console.WriteLine("Validating...{0}", data);

return true; > >'

class AsOperatorApp

{

public static void Main()

{

MyControl myControl = new MyControlO;

ISerializable ser = myControl as ISerializable; if (null != ser)

<

bool success = ser.SaveO;

Console.WriteLine("The saving of - {0}' was "+

"{1}successful",

myControl.data,

(true == success ? "" : "not "));

} else

{ Console.WriteUne("nie ISerializable interface is not implemented.");

} } }

Теперь проверка, гарантирующая правильность приведения, производится только раз, что, думаю, намного эффективнее. А сейчас вновь обратимся к MSIL-коду, чтобы увидеть результаты применения оператора as:

.method public hidebysig static void Main() 11 managed {

.entrypoint

// Code size 67 (0x43) .maxstack 4 .locals (class MyControl V_0,

class ISeriallzable V_1,

bool V_2)

IL_0000: newobj Instance void MyControl::.ctor() IL_0005: stloc.O IL_0006: ldloc.0

IL_0007: isinst ISerializable IL_OOOc: stloc.1 IL_OOOd: ldloc.1 IL_OOOe: brfalse.s IL_0038 IL_0010: ldloc.1

IL_0011: callvirt instance bool ISerializable::Save() IL_0016: stloc.2

IL_0017: Idstr . "The saving of '{0}' was {1}successful" IL_001c: ldloc.0

IL_001d: call instance class System.String FancyControl::get_data()

IL_0022: ldloc.2

IL_0023: brtrue.s IL_002c

IL_0025: Idstr "not "

IL_002a: br.s IL_0031

IL_002c: Idstr

IL_0031: call void [mscorlib]System.Console::WriteLine(class System.String,

class System.Object, class System.Object)

IL_0036: br.s IL_0042

IL_0038: Idstr "The ISerializable interface is not implemented." IL_003d: call void [mscorlib]System.Console::WriteLine(class System.String) IL_0042: ret } // end of method AsOperatorApp::Main



Содержание раздела