- PVSM.RU - https://www.pvsm.ru -
Предлагаю Вам ряд вопросов по C# и .NET в целом, которые могут пригодиться для проведения собеседования или просто помогут лучше понять, как работает платформа .NET. Здесь не будет обычных вопросов о том, чем отличаются ссылочные типы от значимых и тп. Я постарался выбрать самые интересные, над которыми стоит задуматься.
internal class Feedback : System.MulticastDelegate {
// Конструктор
public Feedback(Object object, IntPtr method);
// Метод, прототип которого задан в исходном тексте
public virtual void Invoke(Int32 value);
// Методы, обеспечивающие асинхронный обратный вызов
public virtual IAsyncResult BeginInvoke(Int32 value,
AsyncCallback callback, Object object);
public virtual void EndInvoke(IAsyncResult result);
}
Еще интересный вопрос — почему конструктор класса делегата содержит два параметра, а в коде мы просто передаем указатель на метод (внутрений для CLR, по которому этот метод она найдет)?
delegate void Test(int value);
void A(int v)
{
Console.WriteLine(v);
}
void TestDelegate()
{
var t = new Test(A);
t(1);
}
Все просто — потому что компилятор при создании делегата сам подставляет в конструктор значение параметра оbject. Если метод, которым инициализируется делегат статический, то передается null. Иначе передается объект экземпляра класса, которому принадлежит метод. В этом случае состояние этого объекта может быть изменено через ключевое слово this внутри метода.
delegate int GetValue();
int Value1() { return 1; }
int Value2() { return 2; }
void Test()
{
var v1 = new GetValue(Value1);
var v2 = new GetValue(Value2);
var chain = v1;
chain += v2;
Console.WriteLine(chain());
}
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var p = new Program();
p.Test();
Console.ReadKey();
}
void Test()
{
int pass1 = 5;
object pass2 = "Passing test";
ThreadPool.QueueUserWorkItem((obj) =>
{
Console.WriteLine(pass1);
Console.WriteLine(pass2);
});
}
}
}
.method private hidebysig instance void Test() cil managed
{
// Размер кода: 44 (0x2c)
.maxstack 2
.locals init ([0] class ConsoleApplication1.Program/'<>c__DisplayClass1_0' 'CS$<>8__locals0')
IL_0000: newobj instance void ConsoleApplication1.Program/'<>c__DisplayClass1_0'::.ctor()
IL_0005: stloc.0
IL_0006: nop
IL_0007: ldloc.0
IL_0008: ldc.i4.5
IL_0009: stfld int32 ConsoleApplication1.Program/'<>c__DisplayClass1_0'::pass1
IL_000e: ldloc.0
IL_000f: ldstr "Passing test"
IL_0014: stfld object ConsoleApplication1.Program/'<>c__DisplayClass1_0'::pass2
IL_0019: ldloc.0
// вот создается этот класс!
IL_001a: ldftn instance void ConsoleApplication1.Program/'<>c__DisplayClass1_0'::'<Test>b__0'(object)
IL_0020: newobj instance void [mscorlib]System.Threading.WaitCallback::.ctor(object,
native int)
IL_0025: call bool [mscorlib]System.Threading.ThreadPool::QueueUserWorkItem(class [mscorlib]System.Threading.WaitCallback)
IL_002a: pop
IL_002b: ret
} // end of method Program::Test
А вот описание самого класса и он содержит обсуждаемый метод:
Компилятор определяет, есть ли в лямбда выражении ссылки на локальные переменные. Если нет, то генерируется статический метод (или экземплярный, если в лямбда-выражении присутствуют ссылки на члены экземпляра типа). А если ссылки на локальные переменные присутствуют, то генерируется класс, содержащий нужные поля и метод, описанный в лямбда выражении.
int a = -5;
Console.WriteLine(~a);
Console.WriteLine("{0:x8}, {1:x8}", -5, ~(-5));
// выведет fffffffb, 00000004
Причем для значения 5 выведет -6.
// первое решение
int rand3()
{
int x, y;
do {
x = rand2();
y = rand2();
} while (x == 0 && y == 1);
return x + y;
}
// второе решение
int rand3()
{
int r = 2 * rand2() + rand2();
if (r < 3)
return r;
return rand3();
}
Любая критика приветствуется. Вопросы есть еще по другим темам, если интересно.
Автор: AntonioGrande
Источник [1]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/c-2/257957
Ссылки в тексте:
[1] Источник: https://habrahabr.ru/post/328504/
Нажмите здесь для печати.