Ответы пользователя по тегу C#
  • Сигнатура метода, принимающего/возвращающего в качестве параметра список/массив?

    Vadimyan
    @Vadimyan
    Программист C#
    Доброго дня.
    Нужно выбирать действительно необходимый вам возвращаемый тип. С IEnumerable есть некоторые тонкости, которые необходимо знать и всегда о них помнить. Очень советую обе статьи, еще немного информации о коллекциях есть здесь. Я попробую уместить в паре строк основные правила.

    IEnumerable(T) нужно возвращать только в случаях, когда клиент готов принять итератор, потенциально бесконечный! Фактически, этот интерфейс не стоит использовать почти никогда.
    IReadOnlyCollection(T) нужно возвращать (и передавать в методы) в случаях, когда клиент пользуется данными коллекциями, но не должен изменять их. В большинстве случаев это именно так, можно сказать, что IReadOnlyCollection используется чаще остальных.
    IList(T) и ICollection(T) возвращаются в случае, когда клиенту может понадобиться изменить коллекцию, добавив или удалив элементы. Такие ситуации встречаются крайне редко. Различие в том, что в случае с IList(T) клиент может обращаться к элементу по индексу. Что касается передачи этих интерфейсов в качестве аргумента метода, то это может понадобиться, когда метод модифицирует коллекцию, например, удаляет дублирующиеся элементы или очищает коллекцию от старых данных. Здесь есть выбор между явной работой с коллекцией или же передачей IReadOnlyCollection(T) и возвращением результата того же типа. Зависит от задачи.

    Я бы сказал, что IReadOnlyCollection(T) наиболее предпочтителен в качестве возвращаемого параметра, поскольку при таком подходе код остаётся структурированным - можно быть уверенным, что возвращаемая коллекция не модифицируется ниже по коду.

    p.s. Ах да, напоследок. У вас приведены примеры нетипизированных коллекций, которые медленнее их generic-собратьев из-за упаковки-распаковки. Ими пользоваться стоит только в крайний случаях, пример которым я наспех даже и не приведу.
    Ответ написан
    Комментировать
  • EF CodeFirst: из-за чего ошибка при создание связей?

    Vadimyan
    @Vadimyan
    Программист C#
    Проблема у вас в том, что при удалении объекта User происходит каскадное удаление записей и EF находит в графе зависимостей 2 пути, которые ведут к удалению ForumMessage (User -> ForumMessage, User -> Theme -> ForumMessage). Проблема известная, решения предлагают разные.
    Лично я в аналогичной ситуации чуть сильнее разобрался в предметной области и узнал, что одна из связей является необязательной и может быть nullable. То есть, это скорее баг проектирования модели данных. Например, почему Theme принадлежит к User?
    Ответ написан
  • Какую выбрать книгу по WPF?

    Vadimyan
    @Vadimyan
    Программист C#
    В офисе была только книга Мак-Дональда, в ней много теории, есть примеры, которые сложно использовать в реальной жизни (поскольку WPF без MVVM практически нежизнеспособен), поэтому вначале она мне не понравилась, но позже, при необходимости реализации сложного UI на WPF мы часто к ней возвращались, как справочник её использовать крайне удобно.
    И знание внутренних механизмов работы WPF хорошо помогает в отладке - понимаешь причину ошибок, где-то не всплывает пузырьковое событие, потому что перехватывается внутри, где-то не срабатывает биндинг, поскольку проблемы с привязкой (привязка идёт к свойству объекта, а поменялся сам контекст).
    Ответ написан
    1 комментарий
  • C# двойная лямбда (каррирование)

    Vadimyan
    @Vadimyan
    Программист C#
    Вот пример использования.
    static Func<T1, Func<T2, Func<T3, TResult>>> Curry<T1, T2, T3, TResult> 
        (Func<T1, T2, T3, TResult> function) 
    { 
        return a => b => c => function(a, b, c); 
    }

    Увы, попытки сформулировать объяснение лучше статьи у меня не получилось. Фактически, вы можете вызвать функцию, которая вернёт вам функцию, одним из параметров которой будет переданный в первую функцию параметр.... В общем, из функции двух аргументов получается 2 функции от 1 аргумента, но вторая функция является производной от первой.
    В вашем примере логики немного, но вызов может быть таким:
    var result func("someText")("anotherText");
    При этом значению первого параметра присвоится второй, но т.к. это строки, то с первым ничего не случится.
    Ответ написан
    2 комментария
  • Как правильно хранить и обрабатывать данные на C#

    Vadimyan
    @Vadimyan
    Программист C#
    Если речь идет о параметрах приложения, почему бы не воспользоваться стандартным механизмом конфигурационных файлов .net?
    В сложных случаях, когда параметров много и они разделены на логические группы, можно создать несколько configuration section.
    А в простых сценариях, если вы не боитесь запутаться в именах конфигурационных параметров, можно обойтись просто ConfigurationManager.

    var lastLogin = config.AppSettings["LastLogin"];

    Это стандартный механизм дотнета, не нужно париться с созданием кастомного файла, структурой, проверками.
    Ответ написан
    Комментировать
  • Как в C# получить список открытых сокетов у конкретного процесса?

    Vadimyan
    @Vadimyan
    Программист C#
    Я нашёл два решения, но оба достаточно удручающи.
    1. Через ProcessStartInfo запускать netstat.exe и парсить результаты.
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.IO;
    using System.Text.RegularExpressions;
    
    namespace MyNamespace
    {
        /// <summary>
        /// Static class that returns the list of processes and the ports those processes use.
        /// </summary>
        public static class ProcessPorts
        {
            /// <summary>
            /// A list of ProcesesPorts that contain the mapping of processes and the ports that the process uses.
            /// </summary>
            public static List<ProcessPort> ProcessPortMap
            {
                get
                {
                    return GetNetStatPorts();
                }
            }
    
    
            /// <summary>
            /// This method distills the output from netstat -a -n -o into a list of ProcessPorts that provide a mapping between
            /// the process (name and id) and the ports that the process is using.
            /// </summary>
            /// <returns></returns>
            private static List<ProcessPort> GetNetStatPorts()
            {
                List<ProcessPort> ProcessPorts = new List<ProcessPort>();
    
                try
                {
                    using (Process Proc = new Process())
                    {
    
                        ProcessStartInfo StartInfo = new ProcessStartInfo();
                        StartInfo.FileName = "netstat.exe";
                        StartInfo.Arguments = "-a -n -o";
                        StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
                        StartInfo.UseShellExecute = false;
                        StartInfo.RedirectStandardInput = true;
                        StartInfo.RedirectStandardOutput = true;
                        StartInfo.RedirectStandardError = true;
    
                        Proc.StartInfo = StartInfo;
                        Proc.Start();
    
                        StreamReader StandardOutput = Proc.StandardOutput;
                        StreamReader StandardError = Proc.StandardError;
    
                        string NetStatContent = StandardOutput.ReadToEnd() + StandardError.ReadToEnd();
                        string NetStatExitStatus = Proc.ExitCode.ToString();
    
                        if (NetStatExitStatus != "0")
                        {
                            Console.WriteLine("NetStat command failed.   This may require elevated permissions.");
                        }
    
                        string[] NetStatRows = Regex.Split(NetStatContent, "\r\n");
    
                        foreach (string NetStatRow in NetStatRows)
                        {
                            string[] Tokens = Regex.Split(NetStatRow, "\\s+");
                            if (Tokens.Length > 4 && (Tokens[1].Equals("UDP") || Tokens[1].Equals("TCP")))
                            {
                                string IpAddress = Regex.Replace(Tokens[2], @"\[(.*?)\]", "1.1.1.1");
                                try
                                {
                                    ProcessPorts.Add(new ProcessPort(
                                        Tokens[1] == "UDP" ? GetProcessName(Convert.ToInt16(Tokens[4])) : GetProcessName(Convert.ToInt16(Tokens[5])),
                                        Tokens[1] == "UDP" ? Convert.ToInt16(Tokens[4]) : Convert.ToInt16(Tokens[5]),
                                        IpAddress.Contains("1.1.1.1") ? String.Format("{0}v6", Tokens[1]) : String.Format("{0}v4", Tokens[1]),
                                        Convert.ToInt32(IpAddress.Split(':')[1])
                                    ));
                                }
                                catch
                                {
                                    Console.WriteLine("Could not convert the following NetStat row to a Process to Port mapping.");
                                    Console.WriteLine(NetStatRow);
                                }
                            }
                            else
                            {
                                if (!NetStatRow.Trim().StartsWith("Proto") && !NetStatRow.Trim().StartsWith("Active") && !String.IsNullOrWhiteSpace(NetStatRow))
                                {
                                    Console.WriteLine("Unrecognized NetStat row to a Process to Port mapping.");
                                    Console.WriteLine(NetStatRow);
                                }
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
                return ProcessPorts;
            }
    
            /// <summary>
            /// Private method that handles pulling the process name (if one exists) from the process id.
            /// </summary>
            /// <param name="ProcessId"></param>
            /// <returns></returns>
            private static string GetProcessName(int ProcessId)
            {
                string procName = "UNKNOWN";
    
                try
                {
                    procName = Process.GetProcessById(ProcessId).ProcessName;
                }
                catch { }
    
                return procName;
            }
        }
    
        /// <summary>
        /// A mapping for processes to ports and ports to processes that are being used in the system.
        /// </summary>
        public class ProcessPort
        {
            private string _ProcessName = String.Empty;
            private int _ProcessId = 0;
            private string _Protocol = String.Empty;
            private int _PortNumber = 0;
    
            /// <summary>
            /// Internal constructor to initialize the mapping of process to port.
            /// </summary>
            /// <param name="ProcessName">Name of process to be </param>
            /// <param name="ProcessId"></param>
            /// <param name="Protocol"></param>
            /// <param name="PortNumber"></param>
            internal ProcessPort(string ProcessName, int ProcessId, string Protocol, int PortNumber)
            {
                _ProcessName = ProcessName;
                _ProcessId = ProcessId;
                _Protocol = Protocol;
                _PortNumber = PortNumber;
            }
    
            public string ProcessPortDescription
            {
                get
                {
                    return String.Format("{0} ({1} port {2} pid {3})", _ProcessName, _Protocol, _PortNumber, _ProcessId);
                }
            }
            public string ProcessName
            {
                get { return _ProcessName; }
            }
            public int ProcessId
            {
                get { return _ProcessId; }
            }
            public string Protocol
            {
                get { return _Protocol; }
            }
            public int PortNumber
            {
                get { return _PortNumber; }
            }
        }
    }

    using System;
    
    namespace MyNamespace
    {
        internal class Program
        {
            private static void Main(string[] args)
            {
                foreach (ProcessPort p in ProcessPorts.ProcessPortMap.FindAll(x => x.ProcessName.ToLower().Contains("skype")))
                    //extension is not needed.
                {
                    Console.WriteLine(p.ProcessPortDescription);
                }
    
                foreach (ProcessPort p in ProcessPorts.ProcessPortMap.FindAll(x => x.PortNumber == 4444))
                {
                    Console.WriteLine(p.ProcessPortDescription);
                }
    
                Console.WriteLine("Press any key to continue...");
                Console.ReadLine();
            }
        }
    }

    via. Из недостатков конкретно эта реализация заточена под английскую локализацию винды. Но поправить можно. Ясно, что приложению будет требоваться разрешение на запуск процесса.

    2. Обернуть WinAPI. Штука не для слабонервных:
    //local port in decimal
        int LocalPort = (((int)buffer[nOffset])<<8) + 
            (((int)buffer[nOffset+1])) + 
            (((int)buffer[nOffset+2])<<24) + (((int)buffer[nOffset+3])<<16);

    Этот код я запускать не пробовал и адаптировать его будет значительно сложнее. Но для production-кода он по идее подходит больше.
    Ответ написан
    1 комментарий
  • Какую выбрать тему диплома по специальности АСОИУ?

    Vadimyan
    @Vadimyan
    Программист C#
    У вас осталось очень мало времени для, собственно, реализации, поэтому что-нибудь интересное и актуальное взять вряд ли получиться. А дальше всё зависит от ваших целей и ВУЗа. Если кафедра даёт полную свободу технологий и темы - это очень хорошо.
    Если вы хотите защититься с наименьшими трудозатратами, то стоит выбирать тему исходя из простоты реализации. Я видел "отл" за сайты для школ с расписанием занятий. Написать небольшой таскменеджер для собственных нужд - неплохо. Его всегда можно легко расширить до CRM, добавив проекты к каждой доске задач. Даже Trello некоторые пользуются для простого составления списка покупок.
    Если вы хотите получить какой-то опыт или заинтересовать комиссию на защите, всё гораздо интереснее. Я зацепился за слова "обработка информации" и решил, что это имеет отношение к анализу информации из внешних источников.
    1. Парсинг и обработка цифрового сигнала. Например, в DVB (стандарт цифрового ТВ) идёт много служебной информации, которую можно парсить в потоковом режиме и давать пользователю. Список каналов, программа передач. Только не уверен, можно ли где-то так просто получать в потоке DVB-сигнал или найти его кусок в виде файла.
    2. Сейчас есть попытки развивать открытые данные в России. Можно поискать открытые данные для своего региона или что-нибудь интересное из федерального уровня и красиво это отобразить. Если положить это в открытый доступ, то кто-нибудь даже может сказать спасибо.
    3. Сбор и анализ каких-нибудь данных с сайтов. Вот пример парня, который парсит данные с сайтов знакомств и превращает их в весьма занятную статистику. Здесь будут сложности с обоснованием разработки.
    4. Анализ данных анкетирования. Приведу сложный пример - моей темой диплома была система взаимодействия аутсорсинговой компании с заказчиками. Клиенту давалась анкета на 100 вопросов о проекте (с чьей стороны будет менеджер проекта, требуется ли тестирование исполнителем, как будет происходить приемка), система изучала ответы и могла дать ряд уточняющих вопросов. На выходе был документ, регламентирующий взаимодействие сторон - описывались сценарии работы (dedicated development center model, project outsourcing, etc.), правила распределения ответственности и общения сторон. Можно упростить эту задачу.
    5. Распределенные вычисления. Берем задачу, которая требует значительных вычислительных мощностей и при этом легко делится на отдельные работы. Создаём сервер, который будет принимать на вход условия задачи, разделять их на отдельные задания, отсылать эти задания клиентам, принимать результаты и на выходе давать ответ. Из простого - умножение матриц, чуть занятнее - поиск больших простых чисел.
    6. Помощь кафедре? В одной из курсовых работ я пытался внедрить на кафедру доску объявлений, которая бы дублировала стенды и давала при этом приватные зоны (а ля подфорумы) для преподавателей и каждой группы. Некоторые преподаватели появляются на на работе довольно редко (например, совмещающие с другой работой) и им нужна возможность узнавать о важных объявлениях. Студенты тоже обычно организуются вконтакте, что не всегда и не всем удобно.
    7. Флешка с медицинской картой. все данные хранятся в зашифрованном виде. Приходишь к врачу, даёшь флешку, вводишь пароль (или другой способ ограничения доступа), открывается история болезни. Там могут быть записи разных специалистов, история результатов анализов. Актуально для очень разъездных сотрудников.
    8. Найти проект (на преддипломной практике - в каком-нибудь НИИ вам будут рады :D внутренний проект для какой-нибудь компании; фриланс) и приспособить под диплом его. В этом случае ответственность подстегнёт к лучшей реализации, что положительно скажется и на дипломе.

    В целом, к сожалению, студенческие выпускные работы очень редко находят реальное применение и стремиться к этому бесполезно. Нужно выбирать что-то, исходя из своих интересов и целей.
    Ответ написан
    1 комментарий
  • Ссылочные типы [C#, .NET 4.5]

    Vadimyan
    @Vadimyan
    Программист C#
    Привет, по поводу строк в .net очень хорошо писали/переводили ребята на хабре:
    habrahabr.ru/post/165597
    habrahabr.ru/post/172627
    Если вкратце - string это ссылочный тип с множеством переопределенных операций. Самой главной особенностью является создание новой строки при каждой операции (как у значимых типов), что нужно помнить при разработке. Во второй статье еще описан очень занятный механизм .net - интернирование строк. Неизменяемость строк ставит вопрос об их эффективной конкатинации, на который отвечает тот самый Джон Скит: www.yoda.arachsys.com/csharp/stringbuilder.html

    По стандартам кодирования, если речь идёт о стиле, есть советы самих MS: msdn.microsoft.com/en-us/library/ff926074.aspx
    Resharper в своей стандартной конфигурации во многом повторяет эти советы и для выработки хорошего стиля можно рекомендовать стараться делать "зеленый" код по решарперу. Исключение составляет то, что решарпер любит сворачивать выражения foreach в цепочки вызовов LINQ, что очень негативно скажется на поддерживаемости и отлаживаемости кода.

    Напоследок скажу, что по
    Ответ написан
    Комментировать
  • Как сохранить информации в Лист на ASP.NET MVC 4.0?

    Vadimyan
    @Vadimyan
    Программист C#
    Привет. Я согласен с @foxmuldercp - материалы полезные.
    static-поле в контроллере - худшее из возможных решений. Архитектура MVC предполагает наличие модели, которую вы игнорируете. Контроллер должен работать с неким репозиторием в части извлечение и сохранения данных. Приведу упрощенный пример
    public interface IUsersRepository
    {
        UserInfo SaveUserInfo(UserInfo user);
        IReadOnlyCollection<UserInfo> GetUsers();
    }


    В этом случае ваш контроллер может выглядеть следующим образом:
    (Это тестовый пример, на практике нужно использовать DI через IoC-контейнер для внедрения репозитория)
    public class HomeController : Controller
    {
        private readonly IUsersRepository _usersRepository;
        public HomeController()
        {
            _usersRepository = new UsersRepository();
        }
            
        public ActionResult Index()
        {
            var users = _usersRepository.GetUsers();
            return View(users);
        }
    
        public ActionResult Create()
        {
            return View();
        }
    
        [HttpPost]
        public ActionResult Create(UserInfo userInfo)
        {
            if (ModelState.IsValid)
            {
                _usersRepository.SaveUserInfo(userInfo);
                Users.Add(userInfo);
                return RedirectToAction("Index");
            }
            return View();
        }
    }


    При этом работа по сохранению пользователей переносится на реализацию интерфейса IUsersRepository. В зависимости от ваших потребностей, вы можете реализовать хранение коллекции пользователей в БД, в файле на диске, в оперативной памяти (для этого нужно либо сделать репозиторий синглтоном, либо заговнокодить статическую коллекцию в нём).
    Несколько замечаний напоследок:
    1. Репозитории обычно отвечают за работу с конкретным хранилищем данных на уровне сохрани/удали/извлеки, а места для бизнес-логики не остаётся. Поэтому звеньев может быть еще больше - есть сервис бизнес-логики для работы с пользователями, который через репозиторий извлекает данные, а после формирует модель для отдачи контроллеру. Таким образом из класса EF code first Person может формироваться модель UserInfo.
    2. Еще раз напомню про материалы @foxmuldercp , которые на начальных этапах изучения mvc могут быть очень полезны.
    Ответ написан
    Комментировать
  • Как передать произвольный метод в класс для асинхронного выполнения, отслеживания статуса и получения результата?

    Vadimyan
    @Vadimyan
    Программист C#
    Возможно, до тех пор, как я доберусь до вашего вопроса, кто-то другой вспомнит промышленное решение.
    Я для унификации сигнатур функций использовался вот этим методом:
    habrahabr.ru/post/143465
    То есть, любую функцию с N параметрами при помощи карринга / частичного применения можно привести к виду TResult Method(). Из недостатков - класс FunctionalExtensions у меня содержал порядка десятка методов под разное количество параметров, приводимое к разному числу параметров. Вам удобнее - нужно функции с разным числом параметров привести к одному виду - функции без параметров.
    Ответ написан
    4 комментария
  • Как в WP заблокировать в цикле кнопки на форме?

    Vadimyan
    @Vadimyan
    Программист C#
    Ох. Начнём.
    1. Правильно ли я понимаю, что кнопки генерируются динамически? Или коллекция btn_[i] заполнена заранее и все кнопки в ней есть?
    2. Можно более подробно узнать о сценарии, в котором возникла такая задача? Сейчас неясно в какой момент времени должна происходить смена доступности кнопок.
    3. ViewFirst или ViewModelFirst вы используете?

    В любом случае, если возникла такая ситуация, то шаблон MVVM уже не соблюдается - представление управляет само собой, а не данные управляют представлением. Тут есть несколько вариантов.
    Если использование команд вам не подходит, то в любом случае где-то должна быть та самая переменная со значением, на которую можно забиндиться.
    Если переменная не булевого типа, то сделать это можно через конвертер.
    Если кнопки генерируются в контейнере элементов в зависимости от наполнения коллекции в VM, то можно прибиндиться к элементу коллекции. Если же для коллекции нужно прибиндиться к внешнему свойству, то подойдёт использование RelativeSource.
    Если всё-таки есть переменная в View, которая влияет на доступность кнопок - стоит подумать, как изменить код так, чтобы подобный сценарий не возник. Соблюдать mvvm полностью не всегда просто, но стараться это делать крайне рекомендуется. Что бы там не писали на хабре, но это удобный шаблон, который позволяет не запутаться в коде и вести разработку максимально быстро.

    Я бы всё-таки попросил более подробно описать проблему, сейчас я не понимаю даже, в чём именно возникла загвоздка.
    Ответ написан
  • WCF или программирование сокетов?

    Vadimyan
    @Vadimyan
    Программист C#
    Возможно, стоит сразу взять в приоритет универсальность, скорость разработки и последовательность. С WCF возникают вопросы о том, как и где хостить сервер, а ASP.NET MVC WEB API даст простой старт и нативный хостинг в iis. И кроссплатформенность, конечно. Тот же WCF + REST, но в приятном оформлении.
    Ответ написан
    Комментировать