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

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

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

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

    p.s. Ах да, напоследок. У вас приведены примеры нетипизированных коллекций, которые медленнее их generic-собратьев из-за упаковки-распаковки. Ими пользоваться стоит только в крайний случаях, пример которым я наспех даже и не приведу.
    Ответ написан
  • Как в 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-кода он по идее подходит больше.
    Ответ написан
  • Ссылочные типы [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 или WCF?

    Vadimyan
    @Vadimyan
    Программист C#
    Привет.
    Мне, если речь идёт о связи с веб-мордой и мобильными клиентами (в перспективе не только wp) нравится в качестве бэкенда использовать asp.net mvc web api. Это может показться сложнее простого wcf, тем более, что в wcf есть возможность сделать rest-сервис, поэтому я попробую обосновать плюсы web api.
    1. Универсальность из коробки. web-api работает работает через http и отдаёт данные в json. Их просто собрать и в веб-приложении, при этом любой клиент всегда может обратиться к ним просто послав http-запрос.
    2. mvc web api очень легко прикрутить к фронтенду с помощью knockout.js или angular.js. Фактически, это работает "из коробки" - делаешь запрос, получаешь в js построенную модель.
    3. Даже в настольном приложении через .net всегда можно легко и, главное, асинхронно работать с web api через класс HttpClient (он же есть для WP).
    4. Нет .net? Это просто http-запрос, стучаться легко с других платформ.
    5. Как хостить WCF-сервис? Это не так и сложно, но хочется простоты, всё просто должно работать. web api хостится так же, как обычное asp.net приложение - в iis.
    Ответ написан
  • Как получить один из передаваемых параметров?

    Vadimyan
    @Vadimyan
    Программист C#
    Html.ActionLink(article.Title, 
                    "Item",   // <-- ActionMethod
                    "Login",  // <-- имя контроллера
                    new { id = article.ArticleID }, // <-- Передаваемые параметры.
                    null  // <-- htmlArguments, эта коллекция служит для назначения параметров элементу html, который будет сгенерирован.
                    )

    То есть вам нужно использовать не 4, а 3 параметр метода. При этом в маршрутах должен быть прописан соответствующий вариант параметров (я привёл пример с двумя):
    routes.MapRoute(
                    name: "Default2",
                    url: "{controller}/{action}/d={data_dialog_id}a={data_dialog_title}",
                    defaults: new { controller = "Home", action = "Index", data_dialog_id = UrlParameter.Optional, data_dialog_title = UrlParameter.Optional }
                );


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

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