Wednesday, May 4, 2011

Зачем переписывать у соседа код?

Замечаю что многие студенты вместо того чтобы писать программу сами, переписывают ее у соседа с экрана. Я не возражаю - если хочется работать секретарем/секретаршей, то почему не поучиться быстро набирать на клавиатуре текст? Но какое это отношение имеет к программированию понять не могу.

Представил себе занятия по плаванию - стою я на суше, махаю руками, делаю точно также как тот, который в воде барахтается... Интересно - научусь или нет? Что-то сомнительно.... Или в качалке - один потеет, железки таскает, другой повторяет движения... Возможно даже какой-то результат и будет, но совсем не такой, как у того, который сам.

Мой совет - пишите код сами. Лучше взять задачку попроще и сделать ее. Потом взять сложнее, потом еще сложнее... Ни кто же не гонит, не торопит. Зачем хватать очень сложную задачу, понимая что ее не выполнить и этим оправдывать свое бездействие.

В той же качалке - берем сразу огромный вес, который придавит. Зовем здоровенного качка, просим "подними за меня, я не могу". Ну он-то понятно поднимет, может даже и не вспотеет, здоровый он. А вам-то что с этого толку? Даже морального удовольствия нет...

Tuesday, May 3, 2011

Цитата

Если спросите, то будете дураком 5 минут, а если не спросите, то всю жизнь

Thursday, March 17, 2011

Снова про code style...

Еще раз хочу про стиль кода написать. Замучился доказывать, что писать надо в едином стиле. Вот если кино начинается комедией, а заканчивается детективом, все плюются… Если в часть главы в книге написано от первого лица, а потом резко так, без перехода от третьего – странно все это выглядит. Возникает вопрос что курил автор. А если код так писать, почему-то нормально.
Второй вопрос – заглавные буквы. Заглавная буква это начало мысли, начало чего-то большого, обозначение идеи. Название городов пишут с большой буквы, имена людей и т.д. Но если взять и Просто так начать Писать часть слов Не понятно зачем писать с Большой буквы, то читать это сложно. Ну и про автора такого текста мысли какие-то бродят.. Так почему нужно писать имена переменных именно так:
  private int MyTempVar;
Почему с большой буквы-то? Имя метода (имя человека, города) – это понятно. А тут-то зачем? И читать такой код сложно, хотя можно конечно.
Вообще загадочно, почему то что в обычной жизни никто не делает, в программировании считается нормальным и до хрипоты спорят что можно и так.

Friday, March 4, 2011

Диалоги

Индус (и) разговаривает с боссом (б) в европейской фирме:
б: Is it done?
и: Yes, but not yet.

б: so did you have chance to complete it?
и: yes
б: could you please send it to me
и: I will send it to you tomorrow after it will be finally completed

- Дим, ты все сделал по этой задаче?
- Да, все
- Совсем все или еще что-то осталось?
- Ну тут еще немного...

События


События (event) это почти делегаты, только используется ключевое слово event, что позволяет редактору Visual Studio правильно распределять их по закладкам окна свойств.

Описание класса, использующего события:
namespace EventTest
{
    /// <summary>
    /// Тип метода
    /// </summary>
    public delegate void Progress(int progress);

    public class Parser
    {
        /// <summary>
        /// Описываем событие
        /// </summary>
        public event Progress ProgressHandler;

        /// <summary>
        /// Основной метод
        /// </summary>
        public void Calc()
        {
            for (int i = 0; i < 100; i++)
            {
                // Если обработчик задан - вызываем его
                if (ProgressHandler != null)
                    ProgressHandler(i+1);
            }
        }
    }
}

Использование этого класса:
namespace EventTest
{
    class Program
    {
        static void Main(string[] args)
        {
            // Создаем экземпляр
            Parser parser = new Parser();
            // Вешаем обработчик
            parser.ProgressHandler += new Progress(parser_ProgressHandler);
            // Можно и два метода обработки одного события
            parser.ProgressHandler+=new Progress(parser_ProgressHandlerSecond);
            // Можно описывать обработчики "по месту", хотя это не всегда удобно
            parser.ProgressHandler+= delegate(int progress)
            {
                Console.WriteLine("inline:" + progress);
            };

            // Вызываем метод
            parser.Calc();
        }

        /// <summary>
        /// Этот метод будет вызываться при обработке события
        /// </summary>
        static void parser_ProgressHandler(int progress)
        {
            Console.WriteLine("first:" + progress);
        }

        /// <summary>
        /// Можно вешать и два метода
        /// </summary>
        static void parser_ProgressHandlerSecond(int progress)
        {
            Console.WriteLine("second:" + progress);
        }
    }
}

Saturday, February 26, 2011

Подклассы или типы

В пятницу на очередном занятии возник вопрос - когда лучше делать подклассы, а когда можно обойтись просто свойством (например, сделать тип сущности)? Я так думаю, что если отличий в разных типах не много, то мутить с подклассами не стоит.

Например, если кирпичи в игре Арканоид отличаются только цветом и числом попаданий до уничтожения, то вполне можно обойтись либо типом и тогда возвращать соответсвующие свойства в зависимости от типа:

public Color Foreground()
{
   swith (type)
   {
     case StoneType.One: return Colors.Red;
   ............
}

Либо вообще вынести эти параметры в конструктор и типы не заводить:

public Stone(Color foreground, int countStrike)
{
  .....
}

А вот если отличий будет очень много, то класс будет замусорен кучей if или switch. Вот тогда имеет смысл делать подклассы и разносить логику и код. Разумеется, если какой-то из "типов" имеет дополнительные свойства, то это однозначно нужно выностить в подкласс.

Monday, February 21, 2011

Еще пример про делегаты

Задача такая: по имени функции (математической) получить результат ее вычисления. Самый простой вариант такой:
public class CallFunc1
{
    /// <summary>
    /// Вызываем функцию по имени
    /// </summary>
    public double GetFuncValue(string funcName, double arg)
    {
        switch (funcName.ToUpper())
        {
            case "SIN": return Math.Sin(arg);
            case "COS": return Math.Cos(arg);
            case "TAN": return Math.Tan(arg);
            case "SQRT": return Math.Sqrt(arg);
        }

        throw new ArgumentException("Такой функции нет в списке зарегистрированных функций", funcName);
    }
}

Но тут мы вспоминаем, что квадратный корень нельзя вычислять от отрицательного значения и добавляем еще код:
case "SQRT":
    if (arg < 0)
        throw new ArgumentException("Попытка вычислить квадратный корень от отрицательного числа", "arg");
    return Math.Sqrt(arg);

Потом появляются еще функции и свои проверки… В результате метод GetFuncValue напоминает сборную солянку. А хотелось бы как-то попроще и покрасивее сделать.
С помощью делегатов можно сделать так. Описываем делегат, имеющий сигнатуру метода с одним параметром:
        // Делегат- математический метод
        public delegate double MathFunction(double arg);

А теперь описываем словарь соответствия названий и делегатов таких методов:
        // Список функций
        private Dictionary<string, MathFunction> funcList;

Инициализировать его нужно будет в конструкторе:
    /// <summary>
    /// Конструктор
    /// </summary>
    public CallFunc1()
    {
        // Создаем список функций
        funcList = new Dictionary<string, MathFunction>();
        funcList.Add("SIN", delegate(double arg) {
            return Math.Sin(arg);
        });
        funcList.Add("COS", delegate(double arg)
        {
            return Math.Cos(arg);
        });
        funcList.Add("TAN", delegate(double arg)
        {
            return Math.Tan(arg);
        });
        funcList.Add("SQRT", delegate(double arg)
        {
            if (arg < 0)
                throw new ArgumentException("Попытка вычислить квадратный корень от отрицательного числа", "arg");
            return Math.Sqrt(arg);
        });
    }

Обратите внимание, что реализация делегата сделана прямо “по месту” (это называется анонимными методами – методами без имени).
А с помощью LINQ вызов станет совсем простым делом:
    public double GetFuncValue(string funcName, double arg)
    {
        // Ищем нужную функцию в списке
        var func = funcList.Where(f => f.Key == funcName).Select(f => f.Value).FirstOrDefault();
        // Не нашли - генерируем исключение
        if (func == null)
            throw new ArgumentException("Такой функции нет в списке зарегистрированных функций", funcName);
        // Нашли - вызываем эту функцию
        return func(arg);
    }

Теперь каждое имя функции связанно со своей реализацией и своими ограничениями.