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

    lam0x86
    @lam0x86
    Лучше не держать ничего лишнего в доменных сущностях. На мой взгляд, следует сделать IIssueService, в который перенести методы AcceptToWork, Close и т.д., которые будут принимать на вход ту Issue, над которой выполняется действие.
    И тогда можно конфигурить этот IIssueService различными менеджерами типа IConfigurationManager и IDateTimeProvider.
    Ответ написан
    Комментировать
  • Что я делаю не так при создании свойства зависимости в wpf?

    lam0x86
    @lam0x86
    Скорее всего, canvas1.Background у вас равен Brushes.White. Это синглтон, и он находится в состоянии Frozen (свойство IsFrozen == true), то есть его нельзя менять. Попробуйте указать "#FFFFFF" вместо "White".
    Ответ написан
    3 комментария
  • Как работает AddAfter LinkedList c#?

    lam0x86
    @lam0x86
    Во-первых, привыкайте к стандартам code style. Имена классов, методов и свойств должны начинаться с заглавной буквы. Кроме того избегайте транслитерации - пусть лучше это будет кривой английский, чем "pritok" и "nStran". А в вашем случае, rivers должно быть просто River (единственное число).
    Во-вторых, у LinkedList есть метод AddLast, который добавляет элемент в конец. AddAfter не нужен тут.
    В-третьих, использование LinkedList не оправдано в 99.99% случаев. Есть много материала на эту тему в гугле по запросу "List vs LinkedList performance" (можно поискать на русском "Производительность List и LinkedList").
    В-четвёртых, советую почитать про оператор using и обработку исключений. Ваше решение упадёт при некорректных данных в файле.

    Но это всё лирика. А проблема у вас в том, что вы создаете объект rivers только один раз, а в цикле изменяете его свойства. Получается, что весь ваш список состоит из множества ссылок на один и тот же объект. Если переименуете класс в River, возможно, поймете свою ошибку.
    Ответ написан
    Комментировать
  • Как правильно переопредетиль Equals?

    lam0x86
    @lam0x86
    Во-первых, не забывайте про правило Equals + GetHashCode. При переопределении Equals следует переопределять GetHashCode.

    Во-вторых, переопределять Equals и GetHashCode для изменяемых типов - плохая практика. Всегда есть вероятность, что объект будет использован в HashSet'е или Dictionary, а они требуют неизменности ключа. GetHashCode в идеале должен быть стабильным, то есть всегда возвращать одинаковое значение.

    В третьих (это уже моё субъективное мнение), в большинстве случаев вообще не стоит переопределять эти методы. Кроме, может быть, совсем примитивных типов вроде "строка", "комплексное число", "дата" и т.п. То есть, там, где не может быть никаких разночтений.
    Объекты бизнес-логики чаще всего могут быть одновременно равны и не равны в разных контекстах сравнения. Например, где-то необходимо сравнить двух пользователей по ФИО, а в другом месте - глубокое сравнение всех полей, в т.ч. телефон и имейл. В первом случае объекты могут быть равны, а во втором различны.
    В этом случае стоит написать несколько компараторов, реализовав интерфейс IEqualityComparer, и передавать нужный компаратор в нужном месте, например, в конструктор Dictionary.
    Ответ написан
    Комментировать
  • Что должна возвращать функция в catch блоке?

    lam0x86
    @lam0x86
    Если метод может упасть, при этом не понятно, что он должен в этом случае вернуть, правильнее не ловить исключение вообще. Обрабатывать исключение надо на том уровне, где ясно, как с ним поступить.
    Более продвинутый вариант - ловить исключение, логгировать ошибку, и пробрасывать его дальше в сыром виде (throw;) или в обёртке из business-specific исключения:
    try
    {
      return int.Parse(stringValue);
    }
    catch (FormatException ex)
    {
      Logger.Error(ex);
      throw new MyParserException($"Неверный формат числа {stringValue}", ex);
    }
    catch (OverflowException ex)
    {
      Logger.Error(ex);
      throw new MyParserException($"Выход за допустимый диапазон {stringValue}", ex);
    }
    .
    Ответ написан
    Комментировать
  • Как использовать DependencyProperty?

    lam0x86
    @lam0x86
    Напишите конвертер, который будет реализовывать IMultiValueConverter и перемножать то, что приходит к нему на вход. В xaml-е у secondBox-а определите байндинг не атрибутом, а внутренним элементом, указав в качестве конвертера свою реализацию и внутренние привязки.
    Ответ написан
  • С# .Net 3.5 - есть ли возможность не внедрять сгенерированные Interop .dll файлы?

    lam0x86
    @lam0x86
    Декомпилируйте сгенерированную interop-сборку и добавьте её в свой проект.
    Ответ написан
    2 комментария
  • Как обработать огромный текстовый файл?

    lam0x86
    @lam0x86
    Если строки короткие, то, в принципе, подойдёт такое решение:
    var secondFileLines = new HashSet<string>(File.ReadLines("<файл2>"));
    using (var writer = new StreamWriter("<файл3>"))
    {
        foreach (var line in File.ReadLines("<файл1>"))
        {
            if (!secondFileLines.Contains(line))
            {
                writer.WriteLine(line);
            }
        }
    }


    Если длина строк неограничена, то могут возникнуть проблемы с расходом памяти. В этом случае, всё сильно усложняется. Вам, вероятно, придётся хранить набор хэш-кодов строк из второго файла и сравнивать с хэш-кодом каждой строки из первого. Но тут могут возникнуть ложно-положительные срабатывания, если у разных строк хэши будут совпадать. В этом случае, необходимо будет сравнивать строки посимвольно. Это при идеальной реализации. Впрочем, вероятность совпадения хэшей - 1/2^32. Ну, и надо умножить на 70 миллионов. Если задача позволяет добавить пару лишних строк в результирующий файл, я бы так и поступил.
    Можно немного улучшить алгоритм с хэшами: если, например, использовать 256-битную хэш-функцию, а не стандартную (GetHashCode), можно снизить вероятность ложного срабатывания до 1e-77 (в случае использования SHA1). Думаю, такой мизерной вероятности будет достаточно, чтобы считать задачу решённой. Правда, придётся немного усложнить алгоритм сравнения хэшей - придётся сравнивать массивы.
    Ответ написан
    3 комментария
  • WPF. Какие элементы использовать в мессенджер-приложении?

    lam0x86
    @lam0x86
    Grid явно не подходит в силу отсутствия виртуализации. ListBox на первых порах подойдёт, но затем, скорее всего, вы всё-равно столкнётесь с его ограничениями - он поддерживает только визуальную виртуализацию, но не виртуализацию данных. Скажем, чат из 100 сообщений будет летать, но если вы планируете делать поддержку групповых чатов и с бесконечной историей, то есть вероятность, что приложение будет неотзывчивым уже начиная с 1000 сообщений истории.
    В общем, до этого надо еще дожить. Скорее всего, хватит ListBox (или ListView) как для списка чатов, так и для самих чатов. Идею с Grid-ом советую сразу отбросить - хотя бы из-за прожорливости в плане оперативки.
    Ответ написан
    4 комментария
  • Почему не работает перенаправление ввода/вывода консольного приложения?

    lam0x86
    @lam0x86
    Во-первых, ошибка в том, что вы указываете выходной файл.
    Во-вторых, нужно явно интерпретировать выход как UTF8.

    Process p = new Process();
                p.StartInfo.UseShellExecute = false;
                p.StartInfo.RedirectStandardOutput = true;
                p.StartInfo.FileName = "mystem.exe";
                p.StartInfo.Arguments = "-n input.txt";
                p.Start();
                using (var reader = new StreamReader(p.StandardOutput.BaseStream, Encoding.UTF8))
                {
                    textBox3.Text = reader.ReadToEnd();
                }
                p.WaitForExit();


    Или, может, я не понял вопроса, и вы хотите выводить и в файл, и в выходной поток? Похоже, что данная утилита так не умеет. Придётся сохранять файл самому.
    Ответ написан
  • Как определить что элемент в рабочей области?

    lam0x86
    @lam0x86
    Вообще, в WPF с виртуализацией данных всё довольно печально. Из-за её отсутствия и расплодилось такое количество сторонних гридов. Но тем не менее, можно подписаться на события ItemContainerGenerator-а, который отвечает за визуальную виртуализацию, и подгружать данные во время появления контейнера строк на экране.
    Ответ написан
    Комментировать
  • Как восстановить xaml из baml?

    lam0x86
    @lam0x86
    На сколько я понял из приведенного кода, нужно писать так:
    <Window x:Class="ссылка на класс Login" ...>
    ...
    </Window>
    Ответ написан
  • Как правильно информировать о процессе выполнения задачи?

    lam0x86
    @lam0x86
    Пробовал через класс Progress, но тут мне не понравилось плодить большое кол во классов через
    Progress.Report(new MyReport{...});

    Ничего страшного в этом нет - эти объекты на самом деле тут же умирают, не покидая первого поколения GC.
    Тут другой вопрос более важен: класс Progress устроен так, что маршаллит все репорты в SynchronizationContext, в котором он был создан. В случае с WinForms - это контекст UI-потока. Если ваш Task слишком часто будет вызывать метод Report, это может негативно сказаться на UI-потоке, т.к. он будет забит репортами, каждый из которых он должен обработать. Более того, поскольку маршаллинг в классе Progress асинхронный, есть вероятность, что задача будет выполнена до того, как на UI-потоке обработаются все репорты. Получется запаздывание прогресс-бара от реального прогресса (и вот тут как раз возникает вероятность перехода репортов в Gen1 и Gen2).

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

    public interface IProgressInfo
        {
            bool IsCompleted { get; }
        }
    
        public class ProgressInfo : IProgressInfo
        {
            public ProgressInfo(double completedPercentage, string progressStatusText)
            {
                CompletedPercentage = completedPercentage;
                ProgressStatusText = progressStatusText;
            }
    
            public double CompletedPercentage { get; private set; }
    
            public string ProgressStatusText { get; private set; }
    
            public bool IsCompleted
            {
                get { return CompletedPercentage >= 1; }
            }
        }
    
        public class Progress<T> : IProgress<T> where T : class, IProgressInfo
        {
            private T _previousProgressInfo;
            private volatile T _progressInfo;
            private readonly Action<T> _updateProgressAction;
            private readonly Timer _timer;
            private readonly SynchronizationContext _synchronizationContext;
    
            public Progress(TimeSpan pollingInterval, Action<T> updateProgressAction)
            {
                _synchronizationContext = SynchronizationContext.Current ?? new SynchronizationContext();
                _updateProgressAction = updateProgressAction;
                _timer = new Timer(TimerCallback, null, pollingInterval, pollingInterval);
            }
    
            private void TimerCallback(object state)
            {
                ProcessUpdate();
            }
    
            private void ProcessUpdate()
            {
                var progressInfo = _progressInfo;
                if (_previousProgressInfo != progressInfo)
                {
                    _synchronizationContext.Send(state => _updateProgressAction((T) state), progressInfo);
                }
                _previousProgressInfo = progressInfo;
            }
    
            public void Report(T value)
            {
                _progressInfo = value;
                if (value.IsCompleted)
                {
                    _timer.Dispose();
                    ProcessUpdate();
                }
            }
        }


    Использовать его можно примерно так:

    var workClass = new WorkClass();
    
                var list = Enumerable.Range(1, 1000).Select(i => i.ToString()).ToArray();
                var progress = new Progress<ProgressInfo>(TimeSpan.FromMilliseconds(100), UpdateProgressAction);
    
                await workClass.LongMethod(list, progress);


    где:

    private void UpdateProgressAction(ProgressInfo obj)
            {
                ProgressBar.Value = obj.CompletedPercentage;
                OperationStatus.Text = obj.ProgressStatusText;
                ProgressBarPercentage.Text = string.Format("{0:P}", obj.CompletedPercentage);
            }
    
    internal class WorkClass
        {
            public async Task LongMethod(IReadOnlyList<string> something, IProgress<ProgressInfo> progress)
            {
                await Task.Factory.StartNew(() =>
                {
                    var count = something.Count;
                    for (int i = 0; i < count; i++)
                    {
                        var element = something[i];
                        Thread.Sleep(5);
                        progress.Report(new ProgressInfo((double)(i + 1) / count, element));
                    }
                });
            }
        }
    Ответ написан
    3 комментария
  • Требует ли синхронизации обращение к статическим полям класса, имеющим значимый тип?

    lam0x86
    @lam0x86
    Блокировки не нужны. Но просто так записывать и читать поля из разных потоков тоже нельзя.
    Вот смотрите: предположим, у вас многопроцессорная система. Один поток выполняется на одном процессоре, другой - на другом. У обоих процессоров есть свой кэш (точнее, несколько уровней кэшей). Если первый поток изменяет переменные (не важно, статические они или нет), то они не попадут в оперативную память до тех пор, пока процессор не сбросит кэш при помощи специальной инструкции. Поэтому, второй поток будет продолжать думать, что данные не изменились.
    Для того, чтобы процессоры правильно работали с такими общими переменными придуманы барьеры памяти (memory barriers). Есть несколько способов поставить такие барьеры:
    1) методы Thread.MemoryBarrier() / Thread.VolatileRead() / Thread.VolatileWrite()
    2) добавить к полю модификатор volatile
    3) использовать методы класса Interlocked
    4) Использование блокирующих примитивов синхронизации (Monitor, ReaderWriterLockSlim, Events, Semaphores, Mutexes, etc.)

    Без контекста задачи не ясно, что вам подойдёт в вашей задаче, но похоже, что достаточно пометить поля модификатором volatile.
    Ответ написан
    4 комментария
  • Алгоритмический вопрос от будущего C#.NET-джуниора. С чего начать исследование?

    lam0x86
    @lam0x86
    Последовательность действий такая:
    1) разбиение текста на лексические единицы (в вашем случае значимыми единицами являются слова). Удобно на выходе получать IEnumerable, представляющий ленивый итератор по словам в тексте.
    2) приведение слова к нормальной форме, т. е. к нижнему регистру и, опционально, к общей словоформе (например, для существительных - им. падеж, ед. число, и т.д.)
    3) добавление слова в Dictionary, где ключом является само слово, а значением - счётчик:
    int count;
    dictionary.TryGetValue(word, out count);
    dictionary[word] = count + 1;
    Ответ написан
    Комментировать
  • Как сконвертировать длинное число (строковое представление в hex) в экспоненциальное представление?

    lam0x86
    @lam0x86
    Можно, например, использовать тип BigInteger (из System.Numerics) для парсинга числа, а затем конвертировать его в double. Только надо заранее удалить префикс "0x".
    var parsedValue = BigInteger.Parse("081a8269359ea02246152537192c7827", NumberStyles.HexNumber);
    var result = (double)parsedValue;
    Ответ написан
    Комментировать
  • Какие посмотреть образцовые open-source проекты на WPF?

    lam0x86
    @lam0x86
    Я бы посоветовал почитать про Prism: msdn.microsoft.com/en-us/library/gg406140.aspx
    Хоть это и не готовое приложение, но из документации можно почерпнуть много полезных шаблонов, которые применяются в разработке под WPF.
    Ответ написан
  • Как для двух combobox использовать один List?

    lam0x86
    @lam0x86
    comboBox1.DataSource = new BindingSource() {DataSource = list};
    comboBox2.DataSource = new BindingSource() {DataSource = list};
    Ответ написан
    Комментировать
  • Как решить данную задачу?

    lam0x86
    @lam0x86
    Не слушай их всех =)
    Наверняка, преподаватель хочет видеть решение с замкнутым связным списком. Что-то вроде такого:
    class Program
        {
            static void Main()
            {
                var personList = GenerateList(15); // personList указывает на первого человека в списке
    
                PrintList(personList);
    
                var p = personList;
                while (p != p.NextPerson) // пока человек не остался один в списке
                {
                    #region Этот кусок для корректного вывода списка на экран. Если вывод не нужен, можно убрать
                    if (personList == p.NextPerson)
                    {
                        personList = p.NextPerson.NextPerson;
                    }
                    #endregion
    
                    // <ВсяСоль>
                    p = p.NextPerson = p.NextPerson.NextPerson;
                    // </ВсяСоль>
    
                    // Если убрать верхний регион, то может возникнуть ситуация, когда personList указывает на 
                    // человека, который был удалён из списка. Возникнет бесконечный цикл.
                    PrintList(personList);
                }
            }
    
            // Вывод списка на консоль
            private static void PrintList(Person personList)
            {
                var p = personList;
                do
                {
                    System.Console.Out.Write(p.SequenceNumber);
                    System.Console.Out.Write(" ");
                    p = p.NextPerson;
                } while (p != personList);
                System.Console.Out.WriteLine();
            }
    
            // Генерация списка
            private static Person GenerateList(int n)
            {
                // Начинаем с последнего человека
                var currentPerson = new Person(n);
                var lastPerson = currentPerson;
    
                // затем создаём N-1 человек, указывая его порядковый номер и следующего за ним человека
                for (int i = n - 1; i > 0; i--)
                {
                    currentPerson = new Person(i) { NextPerson = currentPerson };
                }
    
                // последнего человека закольцовываем с первым
                lastPerson.NextPerson = currentPerson;
                return currentPerson;
            }
        }
    
        class Person
        {
            public Person(int sequenceNumber)
            {
                SequenceNumber = sequenceNumber;
            }
    
            public int SequenceNumber { get; private set; }
    
            public Person NextPerson { get; set; }
        }
    Ответ написан
    Комментировать