Перейти из форума на сайт.

НовостиФайловые архивы
ПоискАктивные темыТоп лист
ПравилаКто в on-line?
Вход Забыли пароль? Первый раз на этом сайте? Регистрация
Компьютерный форум Ru.Board » Компьютеры » Прикладное программирование » Программирование в среде .NET (ASP.NET,ADO.NET) на C#/VB.NET

Модерирует : ShIvADeSt

 Версия для печати • ПодписатьсяДобавить в закладки
Страницы: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162

Открыть новую тему     Написать ответ в эту тему

RemComm



Advanced Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Zvezdmii_Lord
Не летают мьютексы так.  
 
Мьютекс именованный - это правильно. Слепое его создание - не совсем правильно, т.к. можно нарваться на гонку (Теоретически. Практическая вероятность крайне мала, но не достигает нуля). Сначала надо пробовать открыть этот именованный мьютекс через OpenExisting или TryOpenExisting.
 
Если мьютекс не открылся - значит код до этого еще не запускался и мьютекс не был создан - создаём этот именованный мьютекс в owned состоянии и пускаем код дальше.  
Если открылся - значит он уже кем-то создан и теперь надо им завладеть через WaitOne(0). Если овладение мьютексом успешное - пускаем код дальше. Если завладеть мьютексом не получилось - значит первая копия кода всё ещё работает, завершаемся.
 
И перед завершением кода не забыть вызвать ReleaseMutex, если мьютекс был захвачен, иначе на следующей попытке захвата существующего мьютекса вылетит AbandonedMutexException.
 
Как-то так:
 

Код:
 
string mxName ="MyMutex";
 
Mutex mx = null;
bool mxAvail = false; // mutex is available flag
 
try  // expecting failures while opeartions of mutex opening/creation
{
  if(!Mutex.TryOpenExisting(mxName, out mx))  // assuming mutex already exists - trying to open it
    mx = new Mutex(true, mxName);                 // mutex hasn't been open - it doesn't exist. Creating a new
  if (mx != null)                                               // check if mutex has been opened/created successfully ...
    mxAvail = true;                                           // ... and set flag
}
catch (Exception e)
{
  // handle exception;
}
 
if (mxAvail)
  if(mx.WaitOne(0))
  {
    // do something...
    mx.ReleaseMutex();
  }
  else
  {
    // other process owns mutex
    // print a message or do nothing
  }
  mx.Dispose(); // or mx.Close() - strongly required.  
}
 

 
В зависимости от реального кода, вместо Dispose(), всё использование мьютекса можно обернуть в using () {...}

Всего записей: 838 | Зарегистр. 30-09-2003 | Отправлено: 06:05 04-08-2019 | Исправлено: RemComm, 02:29 05-08-2019
terz

Junior Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Чайника вопрос.  
 
Коллеги, у меня есть база на MS SQL, в ней написанные и работающие процедуры.  
Теперь встал вопрос изучения C#.  
Что я хочу понять: работа с классами ранее была мне чужда, сейчас читаю книги, теоретически мои задачи укладываются в классы.  
Т.е. есть вот список сделок - для него делается класс mDeals с одним параметром  
id_client, методом Get - и все, что он должен уметь, это по переданному параметру получить все сделки клиента через процедуру на ms sql (entity framework пока принципиально не смотрю).  
 
Правильно ли я понимаю, что работать надо именно так?  Что если потребуется, например, указывать еще и дату начала/конца, то просто добавляю еще два параметра и в вызове метода проверяю, что они установлены?  
 
Для сделки же как таковой параметров будет куда больше, там порядка 20 полей. И должно быть уже два метода - Write and Get.
 
Меня что смущает - что при подобном подходе класс ничем не отличается от процедуры, по сути.  То ли я неверно думаю уже на этапе проектирования, то ли так и должно быть, и зря парюсь.

Всего записей: 71 | Зарегистр. 29-11-2010 | Отправлено: 13:23 03-10-2019 | Исправлено: terz, 14:46 03-10-2019
RemComm



Advanced Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
terz
Класс от процедуры, по сути, таки отличается. Но, метод класса с процедурой сравнить можно. Раз вы недавно изучаете сишарп, то пока делайте так, как понимаете. Вы еще не можете правильно думать на этапе проектирования - у вас нет опыта дизайна кода. Потом, наберетесь опыта, поймете, чем ваш код плох - и перепишете по новому.
 
Есть "умные" дизайны кода, есть не очень, разные стили написания, но все они основаны на базовом функционале языка программирования. По сути, правило одно: то, что не собралось - то гарантированно не работает. Все остальное зависит. Иногда надо бывает объявить метод с 20 параметрами. Иногда это кошерно, а иногда эти 20 параметров надо заменить одним типом, в котором эти параметры реализованы как члены типа. Класс или структура - тоже зависит.
 
С опытом понимание придет.
 
Париться или нет - тоже зависит . Если париться - то понимание приходит быстрей, но требует больше ресурсов на изучение вопроса, материала, интренетов, анализ мыслей и идей. Если не париться - то, все происходит не так быстро. Это уж зависит от ваших целей.

Всего записей: 838 | Зарегистр. 30-09-2003 | Отправлено: 18:53 03-10-2019 | Исправлено: RemComm, 18:57 03-10-2019
terz

Junior Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Спасибо за ответ. Компилируется у меня все.  
 
Но не могу понять сам подход:  
вот сделка. Вот я ее объявил классом. Методов всего два - записать и получить данные.  
Параметров у них не должно быть вообще, таким образом. Но перед тем, как вызвать запись, Write(), я должен проверить, что поля заполнены - введена дата сделки, цена, содержимое и т.п.  
И если нет, то два члена класса ErrCode and ErrMessage заполняю - одно кодом ошибки, другое сообщением. И вроде все красиво.  
Но непонятно, в чем выигрыш по сравнению просто с процедурным подходом. Возможно, в данном конкретном случае его нет просто?  
В скорости кода я точно теряю, писать в классе надо больше.

Всего записей: 71 | Зарегистр. 29-11-2010 | Отправлено: 08:11 13-10-2019
terz

Junior Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Или вот, например:  
Список валют. Получаю его процедурой из базы данных, менятся он не будет. На форме отображается как комбобокс или листбокс. Раньше я бы просто задал источник данных для комбо.  
Нужно ли создавать класс для этого? Очевидно, что класс такой будет статический, в нем буквально два параметра - Id and Currency, заполняться значениями должен уже в конструкторе. Не мудрю ли слишком?

Всего записей: 71 | Зарегистр. 29-11-2010 | Отправлено: 17:48 13-10-2019 | Исправлено: terz, 17:48 13-10-2019
RemComm



Advanced Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
У вас, действительно, слабый бекграунд в ООП. Это и есть основная причина. Вы пытаетесь применить ООП, используя свои навыки процедурного программирования. Это не сработает, потому что, свое, хорошо знакомое, всегда (!) работает лучше. Это надо ломать. Конечно, не имея практики построения дизайнов и архитектур кода и данных вы не сможете описать хороший тип данных в ООП. Как бы вы ни старились. Потому что бекграунда нет.
 
Вам ООП зачем, если вы его не разумеете? Если процедурный стиль вам проще и понятней и (главное) кажется вам лучше - то используйте его.
 
На ООП перейдете, когда для вас станут очевидны его преимущества. Как они вам станут очевидны - никто не знает. Просто вы пишете много кода и использованием ООП и сравниваете его с тем, как бы вы реализовали его с применением процедурного подхода. И это и будет ваш бекграунд. Через какое-то время (может - пара месяцев, может - пара лет), картина для вас станет проясняться и вы сделаете себе мнение. Какое-то время должно пройти. Потом вы поймете, что ООП - есть расширение ПП, только и всего.
 

Цитата:
Очевидно, что класс такой будет статический, в нем буквально два параметра
Совсем не очевидно. Как раз наоборот - нет никаких причин быть ему статическим. И даже наоборот - от никак не сможет быть статическим. Но да то такое... Если для представления данных подходит какой-то из стандартных типов данных - то лучше использовать их. (Стандартные, это те, которые предоставляет .Net). В данном случае, вы неверно реализуете представление, пытаясь все-все-все обернуть в свои типы. ООП - он вовсе не про это.
 
Зачем для этого класс вообще? Вы и теперь можете просто задать источник для комбо. ООП не заставляет вас все оборачивать в свои типы. Как уже написал ранее - можно обходиться стандартными типами. Список - он же и есть список. Делаете List<string>() (или какого типа у вас данные... Currency - наверно, строкового), В цикле обрабатываете данные из датаридера и добавляете ваши валюты в лист. Потом этот лист указываете как источник для combobox. Если надо в комбобоксе вывести названия, а в Selected получить код валюты, то прост используйте словарь: Dictionary<string, int>() (допустим, Currency - строковый и CurrencyCode - цифровой). Так же, в цикле, обрабатываете датаридер и добавляете все валюты в словарь. Потом этот словарь передаете как источник в cоmbobox. Всего 5 строк кода. Можно обойтись и без цикла, если использовать метод ридера AutoMap() или LINQ.
 
ООП (в принципе), есть группировка каких-то данных и методов их обработки в некую единую сущность - тип. Создавая экземпляр типа - объект, вы получаете все определенные свойства и методы как неотъемлемую часть этого объекта. Например, те же заказы. В ПП вы отдельно опишете процедуры валидации заказов, их получения и сохранения. В ООП можно сделать тип данных Заказ и валидацию сделать неотъемлемой частью типа. Для получения и сохранения заказов можно сделать тип ДиспетчепрЗаказов и получение/сохранение заказов сделать частью логики диспетчера. Тогда, можно написать как-то так:
 

Код:
 
public class Order
{
  public int OrderId {get; private set}
  public DateTime OraderDate {get; private set}
  public int Value {get; set}
 
  public Order(int ordId, DateTime ordDT)
  {
    OrderId = ordId;
    OrderDate = ordDT;
  }
 
  public Order(int ordId, DateTime ordDT, int val) : this(ordId, ordDT)
  {
    Value = val;
  }
 
  public bool Validate()
  {
    return Value > 0 ? true : false;
  }
}
 

 

Код:
 
public class OrderDispatcher
{
  public Order Get(int ordId)
  {
    // code to get order by Order ID;
    return ord;
  }
 
  public bool Store(Order ord)
  {
    // code to store order somewhere;
    return opresult;
  }
}
 

 

Код:
 
OrderDispatcher ordDisp = new OrderDispatcher();
Order ord1 = ordDisp.Get(148);
ord1.Value = 12345;
if (ord1.Validate())
{
  ordDisp.Save(ord1);
}
else
{
  // process invalid order;
}
 

 
Таким образом, вы знаете, что если у вас есть некий заказ, то вы легко можете его провалидировать просто вызвав соответствующий метод, потому что в такой реализации, валидация является неотъемлемой частью заказа. В ПП надо было бы вызвать функцию валидации заказа, в которую надо было бы передать все данные из ордера, что не так удобно, как простой вызов метода. Если у вас несколько разных типов заказов и для них нужны разные валидаторы, то в ПП вы их опишете функциями/процедурами, которые не будут привязаны к типам заказов. В ООП вы привяжете конкретный валидатор к конкретному типу заказа. По аналогии с ПП, члены типа - данные и код, логически связанные концепцией типа и сгруппированные в этот самый тип. Поля и свойства типа - это переменные/константы, а методы - подпрограммы или функции.
 
 
Теперь, представим, есть задача:
 
Надо создать в памяти 5 (абстрактных) заказов и выполнить некую аналитику в которой одновременно обрабатываются все 5 заказов. Все заказы имеют одинаковую структуру из 8 полей (произвольного типа), обязательных к заполнению.
 
В ООП можно сделать так:
 
- Один раз объявить тип Order, в котором описаны все 8 полей и методы валидации.
- Один раз объявить тип Analytic, в котором описаны все аналитические методы и вывод на монитор или в файл или в базу. Допустим, аналитика требует предварительной инициализации, поэтому там есть параметрический конструктор, принимающий три (каких-то) параметра.
 
потом весь код будет состоять всего из 7 строк:
 
Пять раз инстанциируется тип Order (создается пять заказов)
Один раз инстанциируется тип Analytic
И один раз вызывается аналитический метод.

Код:
 
Order ord1 = new Order (p1, p2, p3, .... p8);
Order ord2 = new Order (p1, p2, p3, .... p8);
Order ord3 = new Order (p1, p2, p3, .... p8);
Order ord4 = new Order (p1, p2, p3, .... p8);
Order ord5 = new Order (p1, p2, p3, .... p8);
Analytic sam = new Analytic (p1, p2, p3);
sam.Process(ord1, ord2, ord3, ord4, ord5);
 

Ну и все , пожалуй.
Все видно и понятно, хоть и мало отличается от ПП. Вся реализация убрана под капот именно за счет ООП. Чистое ПП такой  простоты не даст.  
 
За для интереса спросите у гугля про "разница между процедурным программированием и ООП". Там, наверняка, найдется полезное и интересное чтиво. Навоза там, да, много, но и жемчуг в нем тоже есть.

Всего записей: 838 | Зарегистр. 30-09-2003 | Отправлено: 19:18 13-10-2019 | Исправлено: RemComm, 03:42 14-10-2019
terz

Junior Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Огромное спасибо за развернутый ответ и пояснения.  
 

Цитата:
У вас, действительно, слабый бекграунд в ООП.

 
Слабый, это не то слово. "Никакой".  Кроме книги Фленова, которая прочитана на 10 часть, ничего не ведаю.  
 
Зачем... Затем, что практически везде требуется ms sql + c#. И если с первым у меня 20 с лишним лет опыта, то со вторым печаль. Фленов пишет, что все в c# должно быть классами, вот и думаю.
 
Почему класс со списком валют видится мне статическим. Его никак не надо надо изменять, просто обращаться c его даннымы, создавать его копии не нужно.
 
А вот что объявить тип Ордер и потом вызвать метод - через объекты проще... Я точно так же создам процедуру, через нее вставлю данные в таблицу tbl_Order 5 раз и потом еще одной процедурой обработаю все пять ордеров. В общем, еще читать и думать. Поспрашиваю еще тут или есть более правильные места для вопросов чайников?  
 
 
 

Всего записей: 71 | Зарегистр. 29-11-2010 | Отправлено: 14:34 15-10-2019 | Исправлено: terz, 15:14 15-10-2019
RemComm



Advanced Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
ООП, ПП, ФП, остальное - это все всего лишь о вкусах и о типах мышления. Если вы привыкли писать в процедурном стиле, то да, в объектном будет трудно. Чтоб писать в объектном - надо мыслить объектами. Мыслить процедурами - не выйдет.
 

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

 
То вы не разобрались. Статический класс - это не про копии, а про экземпляры вообще. Статический класс не может иметь экземпляров, т.е. не возможно создать объект некоего статического типа.
 
Фленов немного неверно пишет и разводит смуту в умах, если пишет, что в C# должно состоять из классов. Это не только не полезно, но, даже и вредною. Увы, невозможно выучить C# прочитав только одну книгу на русском языке. В C# не все состоит из классов. Класс - это всего лишь частный случай ссылочного типа. Наверно, даже стоит обратиться к Рихтеру - никто не знает про .Net больше.
 
Чтоб понять использование той или иной сущности, надо иметь некую стратегию ее использования в коде, юзкейс. Давайте взглянем на ваши валюты. Как вы их хотите использовать в коде? Давайте попробуем прямо сейчас их как-то обернуть в класс. У валюты есть наименование и код и вы видите этот класс статичным:
 

Код:
 
public static class Currency
{
  public static sring Name = "USD";
  public static int Code = 2;
}
 

 
М... , ну и как это можно использовать? А никак. Этот класс не в состоянии описать валюту вообще. Этот класс может описать только конкретную валюту. Создать объект этого типа вы не сможете:
 

Код:
 
Currecncy usd = new Currency(); // compilation error
 

 
Вам придется написать статический класс для каждой валюты. Значит, что-то не так. Перепишем:
 

Код:
 
public class Currency
{
  public sring Name {get; set}
  public int Code {get; set}
  public Currency (string name, int code)
  {
    Name = name;
    Code = code;
  }
}
 

 
Теперь лучше. Можно создавать валюты.

Код:
 
Currency usd = new Currency("usd", 1);
Currency eur = new Currency("eur", 2);
 

Хоть и правильно, но, все-равно, какая-то фигня. Где-то это, наверно, можно использовать, но в комбо вы их, все равно, не передадите. ComboBox в качестве источника принимает IList. Как вы обернете Currency в IList? Никак. И если уж заморачиваться с классом для валют, то попробуем вот так:
 

Код:
 
public class Currencies
{
  private Dictionary<string, int> _currencies = new Dictionary<string, int>();
 
  // indexed property to resolve currency Name to currency Code;
  // isn't used in this example, can't skipped;
  public Code[string currencyName]
    { get { return _currencies[currencyName]; } }
 
  public Currencies()
  { // default constructor; no implementation; }
 
  public void Add Curency(string name, int code)
  {
    _currencies.Add(name, code);
  }  
 
  public List<string> GetAsList()
  {
    return _currencies.Keys;
  }
 
  public Dictionary<string, int> GetAsDict()
  {
    return _currencies;
  }
}
 

 
Ну, наверно... Дальше как-то так:
 

Код:
 
Currencies currencies = new Currencies();
currencies.Add("usr", 1);
currencies.Add("eur", 2);
currencies.Add("bgp", 3);
...
ComboBox.DataSource = currencies.GetAsList();
 

 
Теперь хоть немного похоже на правду. Как вы теперь поняли, статический класс тут не применим никак. Но, повстает вопрос: "а таки шобы шо" в итоге? Весь этот класс, по сути, обертка над Dictionary(). Причем, совершенно бесполезная. Весь функционал можно получить непосредственно из Dictionary(). К тому-же, Dictionary() - это стандартный дженерик и его не надо писать. Он уже есть в составе .Net.
 
Я подозреваю, что существует вообще только один способ научится программированию в каком-то стиле: снова, снова и снова писать. Пусть криво, пусть не понятно даже с ошибками. Разбираясь со всеми непонятными (а порой даже и с понятными) аспектами по очереди. Если более эффективно, то можно ревьювить опернсорс. Просто, идете на тот же гитхаб и просто смотрите, что пишут другие. От простых проектов к сложным. PROS - вы будете набираться опыта из юзкейсов и это будет формировать объектное мышление. CONS - требует очень много времени. Ну и, конечно же, официальный .Net library reference. Вы будете узнавать функциональный состав .Net и это будет избавлять вас от необходимости писать не всегда нужные обертки.
 
Я на C# пишу уже очень долго, но, все рано, открывая какой-то свой исходник полугодовалой давности, я думаю: "о боги, неужели этот хлам написал я, ведь надо было писать совсем по другому". И это постоянное состояние. Эволюция - процесс медленный.
 
Успехов Вам.

Всего записей: 838 | Зарегистр. 30-09-2003 | Отправлено: 20:30 15-10-2019 | Исправлено: RemComm, 20:47 15-10-2019
Rex2701



Newbie
Редактировать | Профиль | Сообщение | ICQ | Цитировать | Сообщить модератору
Подскажите, пожалуйста, такой момент:
Допустим, есть форма с кнопкой. НАДО чтобы все события от кнопки обрабатывались в одном месте.
В событиях кнопки на MouseDown и на MouseUp прописываю один и тот же обработчик: Button_Action.
Получаю автоматически сгенерированный код:

Код:
private void Button_Action(object sender, EventArgs e)
{
 
}

Как теперь внутри написать что-то вроде:

Код:
if (событие == MouseDown)
{
    ...
}
if (событие == MouseUp)
{
    ...
}

 
P.S. в С# практически новичок, раз в пятилетку приходится какую-нибудь мелочь сваять.

Всего записей: 30 | Зарегистр. 11-06-2008 | Отправлено: 10:58 21-11-2019 | Исправлено: Rex2701, 10:59 21-11-2019
mxm1975



Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Может не нужно так делать?
 

Код:
 
        private void ActionHandler(ActionKind actionKind)
        {
            switch (actionKind)
            {
                case ActionKind.ButtonClick:
                    // do something 1
                    break;
                case ActionKind.MouseUp:
                    // do something 2
                    break;
                case ActionKind.MouseDown:
                    // do something 3
                    break;
                default:
                    throw new ArgumentOutOfRangeException(nameof(actionKind), actionKind, null);
            }
        }
 
        private void button1_Click(object sender, EventArgs e)
        {
            ActionHandler(ActionKind.ButtonClick);
        }
 
        private void button1_MouseUp(object sender, MouseEventArgs e)
        {
            ActionHandler(ActionKind.MouseUp);
        }
 
        private void button1_MouseDown(object sender, MouseEventArgs e)
        {
            ActionHandler(ActionKind.MouseDown);
        }
 

Всего записей: 279 | Зарегистр. 31-07-2002 | Отправлено: 01:36 22-11-2019 | Исправлено: mxm1975, 01:37 22-11-2019
Rex2701



Newbie
Редактировать | Профиль | Сообщение | ICQ | Цитировать | Сообщить модератору
mxm1975
Может и не нужно, но что если событий надо обработать не 3, а 20?
 
Лепить 20 обработчиков некрасиво.

Всего записей: 30 | Зарегистр. 11-06-2008 | Отправлено: 09:12 22-11-2019
RemComm



Advanced Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
А, так вон оно чё... Некрасиво, значит.
 
Ну, раз вам не "некрасиво"... То, наверно, можно обратить внимание, что тип параметра там не EventArgs, а MouseEventArgs, у которого есть свойства, Button и Clicks, по которым можно отследить, какая именно кнопка была нажата и сколько раз. Эти свойства, да и сам тип, очень красиво описаны в MSDN. Так же, наверно, все-таки, надо принять во внимание, что там генерируется не одиночное событие, а серия событий. Например, одиночный, двойной и тройной клик вы одним обработчиком будете ловить долго. Но, у вас получится - делайте "красиво".
 
Рассуждения о красоте или некрасоте фич C# - довольно странны от человека, который
Цитата:
в С# практически новичок, раз в пятилетку приходится какую-нибудь мелочь сваять.
, но ОК.
 

Всего записей: 838 | Зарегистр. 30-09-2003 | Отправлено: 09:51 22-11-2019 | Исправлено: RemComm, 10:25 22-11-2019
Zvezdmii_Lord

Newbie
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
приветствую, добавляю камеры IP на форму используя libvlc через rstp. Работать то все работает, только вот если дисконект, то и реконекта нет. Может кто что делал по этому поводу?

Всего записей: 20 | Зарегистр. 25-08-2017 | Отправлено: 23:19 10-12-2019
Basikforreve

Junior Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору

В СиШарпе как можно использовать класс DrawingPanel ? VisualStudio2019 никак не находит его.
 
Он вроде относится к Java.
http://www.buildingjavaprograms.com/drawingpanel-csharp/
 
Где скачать? Или уже есть и достаточно указать референсы на библиотеки?

Всего записей: 117 | Зарегистр. 09-04-2010 | Отправлено: 19:07 05-01-2020
LevT



Platinum Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Есть вот такой код, каким рефакторингом вытащить наружу локальный для лямбды findByName предикат FileMatch?
Надо его переиспользовать, код дублировать некомильфо.
Не пинайте: я в шарпе новичок.
 

Код:

        # файлы с именами вида audit_22.txt надо отсортировать по номеру в имени (index)
        # в классе FileContent два члена FileName и Content
 
        private (int index, FileContent file)[] SortByIndex(FileContent[] files)
        {
            Func<int, string?> findByNameMatchIndex = index =>
            {
                bool FileMatch(string name)
                {
                    return index == Convert.ToInt32(name.
                               Replace("audit_", "").
                               Replace(".txt",""));
                }
 
                return files
                    .Select(file => file.FileName)
                    .First(FileMatch);
            };
         .....

 
Добавлено:
 
Вопрос снят, сам придумал
 

Код:

 
            Func<int, FileContent?> findByNameMatchIndex = index =>
            {
                bool FileMatch(string name)
                {
                    return index == Convert.ToInt32(name.
                               Replace("audit_", "").
                               Replace(".txt",""));
                }
 
                var matchedName = files
                    .Select(file => file.FileName)
                    .First(FileMatch);
 
                return files.First(file => file.FileName == matchedName);
            };

 
Добавлено:
 
 
Нет, пока вопрос не снят
Мне же нужно отсортировать FileContent[] по index  
А стало быть, предикат ещё нужен вне этой функции
 
 
Добавлено:
 
Короче, мне видимо на самом деле нужна функция "Map" из FileContent[] files в Hashtable<Integer, string[]>
Где целый ключ достаётся из строки file.FileName, а string[] это file.Content
 
Или подскажите другой вариант сортировки по ключу.
 
 
 
Добавлено:
Один из вариантов (extension method) нарыл на стековерфлоу и переделал под себя
 

Код:

    public static class Util
    {
        public static IEnumerable<TFileContent> Map<TInteger, TFileContent>(
            this IEnumerable<TInteger> indices,  
            Func<TInteger, TFileContent> indexToContent)
        {
            return indices.Select(index => indexToContent(index));
        }
    }

 
 
Как это вызвать?

Всего записей: 17126 | Зарегистр. 14-10-2001 | Отправлено: 22:48 25-01-2020 | Исправлено: LevT, 00:43 26-01-2020
LevT



Platinum Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Нагородил вот такого, осталось написать return new Tuple[]
 

Код:

        private (int index, FileContent file)[] SortByIndex(FileContent[] files)
        {
            static int FilenameToIndex(FileContent content)
            {
                return Convert.ToInt32(content.FileName.Replace("audit_", "").Replace(".txt", ""));
            }
 
            static string IndexToFilename(int index)
            {
                return $"audit_{index}.txt";
            }
 
            var indices = files.Select((Func<FileContent, int>) FilenameToIndex);
 
            var sortedIndices
                = indices.OrderBy(i => i);
 
            FileContent IndexToContent(int index)
 
            {
                Func<int, FileContent?> findByNameMatchIndex = index =>
                {
                    bool FileMatch(string name)
                    {
                        return index == Convert.ToInt32(name.Replace("audit_", "").Replace(".txt", ""));
                    }
 
                    var matchedName = files.Select(file => file.FileName)
                        .First(FileMatch);
 
                    return files.First(file => file.FileName == matchedName);
                };
 
                return findByNameMatchIndex(index);
            }
 

 
 
Помогите!
Всё это мне помог написать за пару-тройку часов Roslyn в Rider-е.  
CDD (compiler driven development) в действии
 
Это первый C# код в моей жизни
 
Ну и, может, посоветуете что.. упростить, а?
(кроме ручных циклов и ветвлений)
 
 
 
Добавлено:
 
Похоже, что утильный extension метод внизу прошлого поста
  надо опять переписать, чтобы возвращал IEnumerable<Tuple>

Всего записей: 17126 | Зарегистр. 14-10-2001 | Отправлено: 01:33 26-01-2020 | Исправлено: LevT, 02:16 26-01-2020
iNNOKENTIY21



Silver Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
LevT
Не достаточно?:

Код:
fileNames.OrderByDescending(file => file.Replace("audit_", ""));


Всего записей: 3505 | Зарегистр. 16-08-2012 | Отправлено: 11:32 26-01-2020
LevT



Platinum Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
iNNOKENTIY21
 
Спасибо )
С помощью райдера написал вот такое: (здесь ничего не подчёркивает)

Код:

            IOrderedEnumerable<string> orderByDescending = files.Select(file => file.FileName)
                .OrderByDescending(filename => filename.Replace("audit_", ""));
 

 
Помоги пожалуйста дальше
 
 
Добавлено:
 
 
 
Где у нас работу JetBrains Rider обсуждают?
Точнее, dotnetcore-sdk
 
Вот это https://github.com/dotnet/templating/wiki/Available-templates-for-dotnet-new
не работает у меня.
 
Что-то не так делаю, помогите..

Всего записей: 17126 | Зарегистр. 14-10-2001 | Отправлено: 13:48 26-01-2020 | Исправлено: LevT, 14:45 26-01-2020
iNNOKENTIY21



Silver Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
LevT
Дальше я не знаю

Всего записей: 3505 | Зарегистр. 16-08-2012 | Отправлено: 14:47 26-01-2020
LevT



Platinum Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
iNNOKENTIY21
 
Дальше по идее должно быть что-то вроде
 
            files.OrderBy<>(orderByDescending).Aggregate<>({...});
 
Только компилятор требует дать ему <типы>
Я привык уже к джаве, где дженерики работают с точностью до наоборот..
 
Вот "расширяю сознание"
 

Всего записей: 17126 | Зарегистр. 14-10-2001 | Отправлено: 15:08 26-01-2020 | Исправлено: LevT, 15:35 26-01-2020
Открыть новую тему     Написать ответ в эту тему

Страницы: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162

Компьютерный форум Ru.Board » Компьютеры » Прикладное программирование » Программирование в среде .NET (ASP.NET,ADO.NET) на C#/VB.NET


Реклама на форуме Ru.Board.

Powered by Ikonboard "v2.1.7b" © 2000 Ikonboard.com
Modified by Ru.B0ard
© Ru.B0ard 2000-2024

BitCoin: 1NGG1chHtUvrtEqjeerQCKDMUi6S6CG4iC

Рейтинг.ru