Набор интересных головоломок по C#. Часть 2

     C# Puzzle №1 (уровень: начинающий)

     Вы хотели бы увидеть коллекцию, которая чудесным образом создает элемент, как только вы попросите его? Ну, вот она. Опрашиваем коллекцию на существование ключа и, вам будет сообщено, что элемент существует в коллекции.

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Text;

namespace ConsoleApplication
{
class Program
{
static void Main( string[] args )
{
NameValueCollection Collection = new NameValueCollection();

Console.WriteLine(
"NameValueCollection магическим образом создает элементы? " +
Collection["foo"] != null ? " Да, он существует" : "Нет, его нету."
);
}
}
}

     Сможете найти "ошибку"?


     C# Puzzle №2 (уровень: средний)


     Следующий фрагмент кода обычно используется в С/С++ для обмена значений двух целочисленных значений без помощи каких-либо дополнительных переменных:

int x, y;

x ^= y ^= x ^= y;

     Это не работает в C#. Можете ли вы объяснить, почему?


     C# Puzzle №3 (уровень: начинающий)


     Могут ли две статические переменные, которые обращаются к друг другу,  привести к бесконечной рекурсии?

public class A
{
public static int a = B.b + 1;
}

public class B
{
public static int b = A.a + 1;
}

public class MainClass
{
public static void Main()
{
Console.WriteLine( "A.a={0}, B.b={1}", A.a, B.b );
}
}

     Можете ли вы объяснить, каков будет результат (если таковые имеются) приведенного выше кода без компиляции?


     C# Puzzle №4 (уровень: продвинутый)


     В тех случаях когда метод ожидает параметр и возвращает что - то, Вы можете написать:

parameter => expression

вместо:

ReturnType Foo( ParameterType parameter )
{
expression;
}

Вопрос:как Вы предоставите лямбда-выражение для делегата, который не ожидает параметров?

delegate int FooDelegate();
static void Foo( FooDelegate Delegate )
{
Console.WriteLine( Delegate() );
}

static void TheProblem()
{
Foo( * );
}

Ваша цель состоит в том, чтобы заполнить * выше лямбда выражением эквивалентное следующему:

int ConvertThisToLambdaExpression()
{
return 5;
}

     C# Puzzle №5 (уровень: продвинутый)


     Можете предсказать результат выполнения кода без компиляции?

List<int> list = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

list.FindAll( i => { Console.WriteLine( i ); return i < 5; } );

     C# Puzzle №6 (уровень: продвинутый)


     Если Вы правильно решили 5 задачу, то с этой у вас тоже не должно быть проблем:

List<int> list = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

list.Where( i => { Console.WriteLine( i ); return i < 5; } );

     C# Puzzle №7 (уровень: продвинутый)


     Сколько раз будет напечатано X?

List<int> list = new List<int>() { 1, 2, 3 };

list.GroupBy ( i => { Console.Write( "X" ); return i; } );
list.ToLookup( i => { Console.Write( "X" ); return i; } );

В этой задаче необходимо подумать о различии двух методов


     C# Puzzle №8 (уровень: начинающий)


     В приведенном ниже коде есть два варианта: либо компилятор выберет метод из базового класса, имеющие такую же сигнатуру или метод фактической класса, для которого необходимо выполнить преобразование параметра..

class A
{
public void Foo( int n )
{
Console.WriteLine( "A::Foo" );
}
}

class B : A
{
/* A::Foo и B::Foo никак не связаны */
public void Foo( double n )
{
Console.WriteLine( "B::Foo" );
}
}


static void Main( string[] args )
{
B b = new B();
/* Какой Foo будет выбран? */
b.Foo( 5 );
}

Какой метод будет вызван? Можете объяснить поведение компилятора?


     C# Puzzle №9 (уровень: начинающий)


     Рассмотрим объявление делегата, который принимает функцию и возвращает другую функцию:

delegate Func<int, int> FuncConversionDelegate( Func<int, int> Func );

Ваша цель написать лямбда выражение, которое будет изменять знак возвращаемого значения:

FuncConversionDelegate Negation = 
/*
сюда вставте лямбда выражение которое
принимает функцию f и возвращает
функцию g, такую что g(x) = -f(x)
*/;

Чтобы проверить возьмите функцию Identity:

static Func<int, int> Identity = x => x;

и примените Neation:

Negation( Identity )( 5 )

Должно вернуться -5.


     C# Puzzle №10 (уровень: начинающий)


     Возможно ли, чтобы класс А имел доступ к приватным членам класса В? Конечно нет. Это нарушение инкапсуляции - наиболее распространенный ответ. Тем не менее существует по крайней мере один случай, где это на самом деле происходит и даже является очень важным элементом языка.


Поэтому вопрос: C#, в каких обстоятельствах  класс А имеет прямой доступ к закрытым членам другого класса B?


     ОТВЕТЫ


     C# Puzzle №1


     Оператор + имеет больший приоритет чем ?:следовательно сначала происходит конкатенация со строкой, а затем проверка на null.


     C# Puzzle №2


     Перед тем, как выражение вычисляется, значения аргументов помещается в стек, поэтому присваивание  обновляет только переменные, но не аргументы выражения. Выражение осуществляется следующим образом:



  1. Поместим в стек x, y, x и y. Стек выглядит так:


y0
x0
y0
x0

x это x0, y -y0


      2.    Применяем XOR двух верхних значений и сохраняем в x. Стек:



x0 ^ y0
y0
x0

x это x0 ^ y0.
y это y0.


       3.   Применяем XOR двух верхних значений и сохраняем в y. Стек:



x0 ^ y0 ^ y0 = x0
x0

x is x0 ^ y0
y is x0


       4.    Применяем XOR двух верхних значений и сохраняем в x. Стек:


x0 ^ x0 = 0

x is 0
y is x0


     C# Puzzle №3

Это не приведет к бесконечной рекурсии, потому что инициализации будет происходить только один раз. Выходные данные должны быть:

     A.a=2, B.b=1

     Порядок вызова:


  1. Вызывается статический конструктор класса А.
  2. Перед тем, как поле А.а будет проинициализировано, будет вызван статический конструктор B.
  3. Инициализация поля В.b. Поле А.а еще не инициализировано и имеет значение по умолчанию. Происходит  инкрементирование на 1 и сохранение в B.b. Поле теперь равно 1.
  4. Инициализация поля А.а. B.b уже инициализирован и имеет значение 1. Происходит инкрементирование на 1 и сохранение в А.а. Поле теперь равно 2.

     C# Puzzle №4

     Ответ прост: () => 5

     C# Puzzle №5

     В документации говориться "Этот метод выполняет линейный поиск; поэтому он является операцией O(n), где n является значением свойства Count.".  Делегат, передаваемый в качестве аргумента вызывается для каждого элемента в списке. Программа выведет:


1
2
3
4
5
6
7
8
9
10


     C# Puzzle №6

     Список будет пустым. Запрос, представленный данным методом, не выполняется до тех пор, пока не будет произведено перечисление объекта путем непосредственного вызова его метода GetEnumerator или с помощью оператора foreach.

     C# Puzzle №7

     Отличие заключается в том, что ToLookup выполняется немедленно. Выедено будет XXX, вызов GroupBy ничего не выведет.

     C# Puzzle №8

     Будет вызван B:Foo(double n). Потому что компилятор дает приоритет методам из того же класса.

     C# Puzzle №9

     FuncConversionDelegate Negation = func => i => -func(i);

     C# Puzzle №10

     Все вложенные классы имеют доступ к приватным членам "верхнего" класса.

Источник: http://netpl.blogspot.com

7

  1. ShurikEv комментирует...:

    А где ответы? :)

  1. sharok комментирует...:

    В следующем посте напишу...

  1. Анонимный комментирует...:

    >>Поэтому вопрос: C#, в каких обстоятельствах класс А имеет прямой доступ к закрытым членам другого класса B?

    В случае явной реализации интерфейса.

  1. Unknown комментирует...:

    Это набор головоломок очень похож на статью - как не надо писать код.

  1. Unknown комментирует...:

    Правда не все - пару "пазлов" использовать можно :)

  1. Анонимный комментирует...:

    Здравствуйте. Считаю себя не начинающим, но задумался над первым заданием. Озадачился (вроде, как ошибок и нет), посидел, почесал репу, решил на практике проверить. Вот мой код:

    NameValueCollection collection = new NameValueCollection();
    Console.WriteLine(string.Format("Blah-blah-blah {0}", collection["foo"] != null ? "Yes" : " No"));

    И вот что мне выдало:
    Blah-blah-blah No

    Так что тут у меня сейчас двойственное чувство. "То ли я идиот, то ли лыжи не едут." О_о

  1. Алексей комментирует...:

    Нет... просто надо было переписать как есть, а не пользоваться форматом :)
    Оператор "?:", в данном коде, выполняется не на коллекцию, а на весь кусок кода Т.е. он проверяет не равна ли null строка ("NameValueCollection магическим образом создает элементы? " + Collection["foo"]). Просто оператор "+" имеет приоритет выше оператора "?:"

Отправить комментарий