Поиск

Запрос о реализации интерфейса с помощью 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