Рассмотрим эти функции:
static void Take(object o)
{
Console.WriteLine("Received an object");
}
static void Take(int i)
{
Console.WriteLine("Received an integer");
}
Когда я называю "взять" функцию таким образом:
var a = (object)2;
Take(a);
Я :получен предмет
Но если назвать это как:
dynamic b = (object) 2;
Take(b);
Я:получено целое число
Оба параметра (а
& б
) приводятся к объекту
. Но почему компилятор имеет такое поведение?
ВАР
- это просто синтаксический сахар, чтобы позволить типа, которые будут определены РГО.
В ваш код:
var a = (object)2;
эквивалентно:
object a = (object)2;
Вы получите объект, так как вы в коробках 2
на объект.
Для "динамических", вы можете захотеть взглянуть на использование типа Dynamic]. Обратите внимание, что тип является статическим типом, но объект типа Dynamic обходит статическая проверка типов*, то есть, типа вы указали на:
dynamic b = (object) 2;
пропускается, а реально он не будет решен во время выполнения.
Как это'ы решены во время выполнения, я верю, что это'ы гораздо сложнее, чем вы можете себе представить ..
Скажем, у вас есть следующий код:
public static class TestClass {
public static void Take(object o) {
Console.WriteLine("Received an object");
}
public static void Take(int i) {
Console.WriteLine("Received an integer");
}
public static void TestMethod() {
var a=(object)2;
Take(a);
dynamic b=(object)2;
Take(b);
}
}
и я поставил полный Ил(настройки отладка) в задней части моего ответа.
Для этих двух строк:
var a=(object)2;
Take(a);
Ил только:
IL_0001: ldc.i4.2
IL_0002: box [mscorlib]System.Int32
IL_0007: stloc.0
IL_0008: ldloc.0
IL_0009: call void TestClass::Take(object)
Но для этих двух:
dynamic b=(object)2;
Take(b);
из IL_000fдо
IL_007aиз
TestMethod. Это не'т вызвать
взять(объект) " или " взять(инт) прямо, но вызывает метод такой путь:
object b = 2;
if (TestClass.<TestMethod>o__SiteContainer0.<>p__Site1 == null)
{
TestClass.<TestMethod>o__SiteContainer0.<>p__Site1 = CallSite<Action<CallSite, Type, object>>.Create(Binder.InvokeMember(CSharpBinderFlags.ResultDiscarded, "Take", null, typeof(TestClass), new CSharpArgumentInfo[]
{
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType | CSharpArgumentInfoFlags.IsStaticType, null),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)
}));
}
TestClass.<TestMethod>o__SiteContainer0.<>p__Site1.Target(TestClass.<TestMethod>o__SiteContainer0.<>p__Site1, typeof(TestClass), b);
Полный иль TestClass
:
.class public auto ansi abstract sealed beforefieldinit TestClass
extends [mscorlib]System.Object
{
// Nested Types
.class nested private auto ansi abstract sealed beforefieldinit '<TestMethod>o__SiteContainer0'
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
01 00 00 00
)
// Fields
.field public static class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite, class [mscorlib]System.Type, object>> '<>p__Site1'
} // end of class <TestMethod>o__SiteContainer0
// Methods
.method public hidebysig static
void Take (
object o
) cil managed
{
// Method begins at RVA 0x2050
// Code size 13 (0xd)
.maxstack 8
IL_0000: nop
IL_0001: ldstr "Received an object"
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ret
} // end of method TestClass::Take
.method public hidebysig static
void Take (
int32 i
) cil managed
{
// Method begins at RVA 0x205e
// Code size 13 (0xd)
.maxstack 8
IL_0000: nop
IL_0001: ldstr "Received an integer"
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ret
} // end of method TestClass::Take
.method public hidebysig static
void TestMethod () cil managed
{
// Method begins at RVA 0x206c
// Code size 129 (0x81)
.maxstack 8
.locals init (
[0] object a,
[1] object b,
[2] class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo[] CS$0$0000
)
IL_0000: nop
IL_0001: ldc.i4.2
IL_0002: box [mscorlib]System.Int32
IL_0007: stloc.0
IL_0008: ldloc.0
IL_0009: call void TestClass::Take(object)
IL_000e: nop
IL_000f: ldc.i4.2
IL_0010: box [mscorlib]System.Int32
IL_0015: stloc.1
IL_0016: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite, class [mscorlib]System.Type, object>> TestClass/'<TestMethod>o__SiteContainer0'::'<>p__Site1'
IL_001b: brtrue.s IL_0060
IL_001d: ldc.i4 256
IL_0022: ldstr "Take"
IL_0027: ldnull
IL_0028: ldtoken TestClass
IL_002d: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_0032: ldc.i4.2
IL_0033: newarr [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo
IL_0038: stloc.2
IL_0039: ldloc.2
IL_003a: ldc.i4.0
IL_003b: ldc.i4.s 33
IL_003d: ldnull
IL_003e: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)
IL_0043: stelem.ref
IL_0044: ldloc.2
IL_0045: ldc.i4.1
IL_0046: ldc.i4.0
IL_0047: ldnull
IL_0048: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)
IL_004d: stelem.ref
IL_004e: ldloc.2
IL_004f: call class [System.Core]System.Runtime.CompilerServices.CallSiteBinder [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.Binder::InvokeMember(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags, string, class [mscorlib]System.Collections.Generic.IEnumerable`1<class [mscorlib]System.Type>, class [mscorlib]System.Type, class [mscorlib]System.Collections.Generic.IEnumerable`1<class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo>)
IL_0054: call class [System.Core]System.Runtime.CompilerServices.CallSite`1<!0> class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite, class [mscorlib]System.Type, object>>::Create(class [System.Core]System.Runtime.CompilerServices.CallSiteBinder)
IL_0059: stsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite, class [mscorlib]System.Type, object>> TestClass/'<TestMethod>o__SiteContainer0'::'<>p__Site1'
IL_005e: br.s IL_0060
IL_0060: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite, class [mscorlib]System.Type, object>> TestClass/'<TestMethod>o__SiteContainer0'::'<>p__Site1'
IL_0065: ldfld !0 class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite, class [mscorlib]System.Type, object>>::Target
IL_006a: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite, class [mscorlib]System.Type, object>> TestClass/'<TestMethod>o__SiteContainer0'::'<>p__Site1'
IL_006f: ldtoken TestClass
IL_0074: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_0079: ldloc.1
IL_007a: callvirt instance void class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite, class [mscorlib]System.Type, object>::Invoke(!0, !1, !2)
IL_007f: nop
IL_0080: ret
} // end of method TestClass::TestMethod
} // end of class TestClass
ВАР
- это статически типизированный`При этом вы видите, что разрешение перегрузки происходит во время работы на "динамичной".
Так что переменная b
держит инт
dynamic b = (object) 2;
Take(b);
Что's причина, почему брать(б);звонки
принимать(инт я)`
static void Take(int i)
{
Console.WriteLine("Received an integer");
}
Но в случае ВАР а = (Объекта)2
переменная а
держит как 'объект'
var a = (object)2;
Take(a);
Что's причина, почему принимают(а); призывает взять(объект o)
static void Take(object o)
{
Console.WriteLine("Received an object");
}
Постановление целочисленный аргумент боксировал происходит во время компиляции. Вот Ил:
IL_000d: box [mscorlib]System.Int32
IL_0012: stloc.0
IL_0013: ldloc.0
IL_0014: call void ConsoleApp.Program::Take(object)
Вы можете увидеть его в "объект" перегрузка в себя время компиляции.
При использовании "динамических" - связующее выполнения входит в картину. "динамических" не только можно решить в управляемом c# объекты, а также на управляемых объектов, таких как COM объекты или объекты JavaScript дается во время выполнения подшивки существует для этих объектов.
Вместо того, чтобы показывать Ир, я'подскажите код декомпилированный (легче читать):
object obj3 = 2;
if (<Main>o__SiteContainer0.<>p__Site1 == null)
{
<Main>o__SiteContainer0.<>p__Site1 = CallSite<Action<CallSite, Type, object>>.Create(Binder.InvokeMember(CSharpBinderFlags.ResultDiscarded, "Take", null, typeof(Program), new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.IsStaticType | CSharpArgumentInfoFlags.UseCompileTimeType, null), CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) }));
}
<Main>o__SiteContainer0.<>p__Site1.Target(<Main>o__SiteContainer0.<>p__Site1, typeof(Program), obj3);
Вы видите, что взять
метод решены во время выполнения подшивки во время выполнения, а не компиляции. Таким образом, это позволит решить его фактический тип.
Если вы посмотрите на C# спецификация:
Способ 1.6.6.5 перегрузки
перегрузка методов позволяет использовать несколько методов в одном классе, чтобы иметь такое же имя, как они обладают уникальной подписи. При компиляции вызов перегруженного метода, то компилятор использует разрешение перегрузки для определения конкретного метода для вызова.
И:
7.5.4 проверка во время компиляции динамического разрешения перегрузки
для большинства динамически привязанные операций набор возможных кандидатов на разрешение неизвестно в compiletime. В некоторых случаях, однако набор кандидатов известен во время компиляции:
- статические вызовы методов с динамическим аргументы
- экземпляр вызовы метода, когда приемник не является динамическим выражением
- индексатор звонки, когда приемник не является динамическим выражением
- вызовы конструктора с динамическими аргументами
В этих случаях ограниченного времени компиляции выполняется проверка для каждого кандидата, чтобы увидеть, если любой из них может применить во время выполнения
Так, в первом случае, ВАР
не динамический, разрешение неоднозначностей найдете способ перегрузки по компиляции.
Но в вашем втором случае, вы звоните статический метод с динамическим аргументы, разрешение неоднозначностей найдете способ перегрузки во время выполнения, а не
Чтобы помочь понять резолюции типа в вашем случае для динамических переменных.
Возьмите(б); //видим здесь тип Б при наведении указателя мыши над ним, будет инт`
это явно означает, что код:
динамичной B = (объекта)2
не конвертировать 2 на объект, когда назначена динамическая переменная и B остается инт
Далее комментировать ваши перегрузки возьмите(инт я)метод, и затем поставить точку останова на строку берите(Б)
(то же: типа " Б " еще
инт
) но когда вы запустите его, вы увидите напечатанные значение: получил
объект.
Теперь, изменить свой "динамическая" переменная звонить в ниже код:
Взять((объекту)б); //это теперь печатает "и получил объект"
в
динамичной B = (долго)2;
Возьмите(б); // это теперь печатает получил объект, потому что нет перегрузки метода, которые можно долго и наиболее подходящей перегрузки является тот, который принимает объект
.`
это потому, что: наиболее подходящий тип решены для динамической переменные по значению он занимает во время выполнения, а также наиболее подходящий способ перегрузки называться будет решен во время выполнения динамических переменных .
В первом случае объект var означает, `чтобы
взять(объект o) называется. Во втором случае можно использовать "динамический" тип и несмотря на то, что вы'вэ коробке вашего типа int
она все еще имеет информацию о нем's тип -инт
так что лучший метод подбора называется.