Задать вопрос
  • Не понимаю в чем проблема?

    Casper-SC
    @Casper-SC
    Программист (.NET)
    Вот так работает. Проверил.

    Вместо типа Image лучше укажи тип Graphic, если этот скрипт будет только менять цвет. Ну и переменную в таком случае назови _graphics, а не _image.

    using System;
    using UnityEngine;
    using UnityEngine.EventSystems;
    using UnityEngine.UI;
    
    namespace Assets.Scripts
    {
        public class BuildManager : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
        {
            private Image _image;
    
            void Start()
            {
                _image = GetComponent<Image>();
    
                if (_image is null)
                {
                    throw new NullReferenceException(
                        $"The component of the type \"{nameof(Image)}\" not found.");
                }
            }
    
            void Update()
            {
            }
    
            public void OnPointerEnter(PointerEventData eventData)
            {
                _image.color = Color.green;
            }
    
            public void OnPointerExit(PointerEventData eventData)
            {
                _image.color = Color.white;
            }
        }
    }
    Ответ написан
    Комментировать
  • Как сделать таймер после которого запустится код?

    Casper-SC
    @Casper-SC
    Программист (.NET)
    using System;
    using System.Diagnostics;
    using System.Windows.Forms;
    
    namespace WinFormsApp
    {
        public partial class MainForm : Form
        {
            private readonly Timer _timer;
            private int _counter;
    
            public MainForm()
            {
                InitializeComponent();
    
                _timer = new Timer();
                _timer.Interval = 500;
                _timer.Tick += OnTimerTick;
            }
    
            private void OnFormLoad(object sender, EventArgs e)
            {
                _timer.Start();
            }
    
            private void OnTimerTick(object sender, EventArgs e)
            {
                _label.Text = $"{nameof(OnTimerTick)}. {(++_counter).ToString()}";
            }
        }
    }
    Ответ написан
  • С чего начать новичку в изучении c# для gamedev?

    Casper-SC
    @Casper-SC
    Программист (.NET)
    Для C# (пишется с большой буквы) установи cреду разработки Visual Studio Community (ссылка).

    В первую очередь тебе нужно выучить C#. Чтобы у тебя дошло до автоматизма написание кода. Первое время ты будешь сильно подвисать на каждой мелочи. Простейшие ошибки будут ставить в тупик. Наверняка, сюда задавать вопросы, что нормально. Это дело не быстрое, невозможно с полного нуля за неделю всё выучить, уйдёт от полугода. И нужно на это будет тратить много времени, желательно даже каждый день. Без знания языка и умения писать в стиле ООП простые приложения я уверен, что в Unity делать нечего.

    Рекомендую создать Решение (Solution) на C# в Visual Studio и в него добавлять проекты по темам из книги.
    Пример проектов в решении:
    Изучение C# (.sln)
    1. Переменные, циклы (.csproj)
    2. Классы (.csproj)
    3. Наследование (.csproj)
    4. Делегаты и события (.csproj)
    Только проекты называй по-английски.
    Прочитал главу, сделал примеры из книги, написал везде комментарии с пояснениями. Делай так, чтобы потом можно было вернуться к этим проектам и быстро вспомнить, что забылось. После того как ты будешь много времени тратить на обучение и чтение книги, у тебя всё лучше и лучше будут запоминаться детали языка. Именно за счёт траты большого кол-ва времени и обучения на длительном промежутке времени всё и выучится само. Я не зубрил ничего почти.

    Очень хорошее объяснение по C# здесь. Сразу скажу, уроки очень старые, но очень хорошие (там про платформу .NET Framework, но ничего нет про .NET Core, а теперь уже просто .NET (начиная с 5) и многого другого). Можно посмотреть эти уроки, после них начать читать книгу по C#, пусть из уроков много будет знакомо, но, скорее всего, в книге ты узнаешь новые детали и учить будет легче.

    Ещё такой курс более современный, его не смотрел.

    Кстати, чтобы не терять интерес, ты конечно можешь установить себе Unity, найти уроки по созданию 2D платформера, даже начать делать по урокам первую игру, но я тебе советую периодически как посидел над Unity возвращаться к книге и читать её дальше и так пока всю не прочитаешь. Я так и учил C#. Писал приложение, так как именно это было интересно, и периодически возвращался к книге.

    Алгоритмы. Можешь почитать хотя бы что-то простое для начала. Например,
    Алгоритмы. Вводный курс | Кормен Томас Х.

    https://qna.habr.com/q/848533#answer_1745621

    Книги есть такие:
    C# 9.0. Справочник. Полное описание языка (ссылка)
    Язык программирования C# 7 и платформы .NET и .NET Core | Джепикс Филипп, Троелсен Эндрю (ссылка)

    Возможно даже
    C# для чайников | Мюллер Джон Поль, Семпф Билл (здесь C# 7.0). ISBN: 978-5-907144-43-9
    Ответ написан
    7 комментариев
  • Проверить наличие элемента в json?

    Casper-SC
    @Casper-SC
    Программист (.NET)
    Сделай свойство Nullable и если оно будет null, значит значение не пришло совсем. Думаю, это самый простой вариант, если тебя не устраивает значение 0 по умолчанию для типа int, которое будет таковым, если даже не пришло значение того свойства.

    public class Competitive
    {
        [JsonProperty("CurrentSeasonGamesNeededForRating")]
        public int? CurrentSeasonGamesNeededForRating { get; set; }
    
        [JsonProperty("SeasonalInfoBySeasonID")]
        public object SeasonalInfoBySeasonID { get; set; }
    }
    Ответ написан
    1 комментарий
  • Хочу изучать c# и хотела приобрести macbook pro m1 стоит ли покупать его?

    Casper-SC
    @Casper-SC
    Программист (.NET)
    У меня MacBook Pro (не M1). Я думаю нет разницы говорим мы про M1 или какой-то другой (обновлено: разница есть). Если будешь использовать специфичные для винды технологии, то придётся поставить винду, что мне и пришлось сделать (UWP). Для себя понял одно, мне MacOS не нужна и неинтересна, если и работаю за ноутом, то только в винде. При этом я не фанат винды, просто она для меня удобнее. Макбук интересен первую неделю, когда наконец-то купил, что так давно хотел, ведь это так необычно, MacOS! А ноут стоит космических денег (мой больше 200 стоит). Купил, открыл, поигрался, всё прикольно, интересно. Работаю на винде. На MacOS можно будет использовать среду разработки Rider. В метро не взять и не открыть, ведь если у тебя макбук, то ты должен ездить на ламборгини, или летать на вертолёте. Будешь постоянно встречать улыбки (смотрите, с макбуком в метро!!!). Ой, меня понесло не туда.
    Ответ написан
    8 комментариев
  • Почему при запросе объекта стиля, получается null?

    Casper-SC
    @Casper-SC
    Программист (.NET)
    Как вариант, можно создать окно, в котором задать заранее определённые стили, задать им TargetType и это надо сделать. Задать каждому стилю уникальный ключ. Создать в Code Behind окна свойство с текущим стилем и его менять. К этому свойству можно прибиндиться TextBlock(ом). Можно всё это сделать красивее и т.д., но суть из примера будет ясна, думаю.

    Вот можно посмотреть как здесь предлагают Changing the styles at runtime in WPF

    <Window
        x:Class="Monitor.SomeWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:local="clr-namespace:Monitor"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        Title="SomeWindow"
        Width="800"
        Height="450"
        mc:Ignorable="d">
        <Window.Resources>
            <Style
                x:Key="BaseFontFamily"
                TargetType="TextBlock">
                <Setter Property="FontSize" Value="90" />
            </Style>
            <Style
                x:Key="Numbers1Style"
                BasedOn="{StaticResource BaseFontFamily}"
                TargetType="TextBlock">
                <Setter Property="Foreground" Value="LightCoral" />
            </Style>
            <Style
                x:Key="Numbers2Style"
                BasedOn="{StaticResource BaseFontFamily}"
                TargetType="TextBlock">
                <Setter Property="Foreground" Value="Bisque" />
            </Style>
        </Window.Resources>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="*" />
                <RowDefinition Height="*" />
            </Grid.RowDefinitions>
            <TextBlock
                Grid.Row="0"
                HorizontalAlignment="Center"
                VerticalAlignment="Center"
                Style="{Binding TimeBlockStyle, RelativeSource={RelativeSource AncestorType=local:SomeWindow}}"
                Text="{Binding Path=RightTeam.TeamCounter, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" />
            <Button
                Grid.Row="1"
                Click="OnButtonClick" />
        </Grid>
    </Window>


    public partial class SomeWindow : Window
    {
        public static readonly DependencyProperty TimeBlockStyleProperty = DependencyProperty.Register(
            nameof(TimeBlockStyle), typeof(Style), typeof(SomeWindow), new PropertyMetadata(default(Style)));
    
        public Style TimeBlockStyle
        {
            get { return (Style)GetValue(TimeBlockStyleProperty); }
            set { SetValue(TimeBlockStyleProperty, value); }
        }
    
        public SomeWindow()
        {
            InitializeComponent();
            TimeBlockStyle = (Style)Resources["Numbers1Style"];
        }
    
        private void OnButtonClick(object sender, RoutedEventArgs e)
        {
            TimeBlockStyle = (Style)Resources["Numbers2Style"];
        }
    }
    Ответ написан
    5 комментариев
  • Как пeредать const char* в c++ фунцию из c#?

    Casper-SC
    @Casper-SC
    Программист (.NET)
    Ответ написан
    Комментировать
  • Как мне это реализовать в List?

    Casper-SC
    @Casper-SC
    Программист (.NET)
    Только вот использовать LINQ нужно с осторожностью. Лично я бы вообще не использовал его в том же Update или любом другом месте, где часто вызывается код.
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using UnityEngine;
    
    [System.Serializable]
    public class TestEvent
    {
        [SerializeField] private int _b;
    
        public int B => _b;
    }
    
    public class TestScript : MonoBehaviour
    {
        [SerializeField] private List<TestEvent> _testEvents;
    
        private int a = 3;
    
        void Start()
        {
            var events = _testEvents
                .Where(item => item.B == a)
                .ToArray();
        }
    }


    Тоже самое, но без LINQ. Чисто показать принцип, так как это элементарная задача, а ты этого не сделал, значит нужно учиться. Если кол-во элементов в List _testEvents небольшое всегда, я бы ещё создавал var results = new List(); с указанием capacity равному _testEvents.Count. То есть так var results = new List(_testEvents.Count);
    public class TestScript : MonoBehaviour
    {
        [SerializeField] private List<TestEvent> _testEvents;
    
        private int a = 3;
    
        void Start()
        {
            var events = GetEvents(_testEvents, item => item.B == a);
        }
    
        private static List<TestEvent> GetEvents(
            IEnumerable<TestEvent> testEvents, Func<TestEvent, bool> predicate)
        {
            var results = new List<TestEvent>();
            foreach (var item in testEvents)
            {
                if (predicate(item))
                {
                    results.Add(item);
                }
            }
            return results;
        }
    }


    Продублирую решение из комментариев:
    public class TestScript : MonoBehaviour
    {
        [SerializeField] private List<TestEvent> _testEvents;
    
        private int a = 3;
    
        void Start()
        {
            var element = GetFirstOrDefault(_testEvents, item => item.B == a);
            if (element is not null)
            {
                c = element.c;
                r = element.r;
                u = element.u;
            }
        }
    
        // Если совпадение не найдено, то вернуть значение по умолчанию.
        private static T GetFirstOrDefault<T>(IEnumerable<T> items, Func<T, bool> predicate)
        {
            foreach (var item in items)
            {
                if (predicate(item))
                {
                    return item;
                }
            }
    
            return default;
        }
    }
    Ответ написан
  • Книги по C# с паттернами и примерами архитектуры?

    Casper-SC
    @Casper-SC
    Программист (.NET)
    Принципы, паттерны и методики гибкой разработки на языке C# | Мартин Роберт С., Мартин Мика (ссылка)
    Ответ написан
    6 комментариев
  • Почему cout не выводит сообщение?

    Casper-SC
    @Casper-SC
    Программист (.NET)
    Ты не вызывал показ сообщения в случае успеха. Немного причесал код и удалил то, что ты можешь просто скопировать из своего кода обратно. Я бы на твоём месте сразу учился писать код так, чтобы каждая функция отвечала за какой-то свой один функционал. Не смешивай всё в одном месте.

    #ifdef _WIN32
    #include <windows.h>
    #endif
    
    #include <iostream>
    #include <fstream>
    #include <string>
    
    bool IsLoggedIn()
    {
        using namespace std;
    
       // ...
    
        return un == username && pw == password;
    }
    
    int main()
    {
        using namespace std;
    
    #ifdef _WIN32
        // https://habr.com/ru/sandbox/108750/
        // Устраняет проблемы выводом кириллицы на консоль Windows
        // Файл должен быть сохранён с кодировкой Windows 1251
        SetConsoleCP(1251);
        SetConsoleOutputCP(1251);
    #endif
    
        int choice;
        do
        {
            cout << "1: Register\n2: Login\n Your choice: ";
            cin >> choice;
    
            if (choice == 1)
            {
                // ...
            }
            else if (choice == 2)
            {
                bool status = IsLoggedIn();
                if (!status)
                {
                    cout << "False Login!\n";
                }
                else
                {
                    cout << "Succesfully logged in!\n";
                }
    
    #ifdef _WIN32
                system("pause");
    #endif
                return status ? 1 : 0;
            }
    
        } while (choice == 1);
    }
    Ответ написан
  • Как создавать несколько объектов класса в цикле?

    Casper-SC
    @Casper-SC
    Программист (.NET)
    Program.cs
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Text;
    using System.Text.Encodings.Web;
    using System.Text.Json;
    using System.Text.Unicode;
    
    namespace ConsoleApp
    {
        class Program
        {
            static void Main(string[] args)
            {
                // Чтение JSON из файла и десериализация.
                string pathToFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "PartnerData.json");
                string jsonText = File.ReadAllText(pathToFile, Encoding.UTF8);
                var parterAddressesFromFile = JsonSerializer.Deserialize<TriggerData>(jsonText);
    
                // Вывод на консоль.
                Display(parterAddressesFromFile);
    
                // Создание нового экземпляра класса TriggerData и его заполнение данными.
                var data = new TriggerData()
                {
                    PartnerAddresses = new List<PartnerAddress>()
                    {
                        new PartnerAddress()
                        {
                            Type = "Тип 0001",
                            Country = "Страна 0001",
                            Region = "Регион 0001",
                            City = "Город 0001",
                            Presentation = "Представление 0001",
                        },
                        new PartnerAddress()
                        {
                            Type = "Тип 0002",
                            Country = "Страна 0002",
                            Region = "Регион 00021",
                            City = "Город 0002",
                            Presentation = "Представление 0002",
                        }
                    }
                };
    
                // Сериализация.
                var options = new JsonSerializerOptions
                {
                    Encoder = JavaScriptEncoder.Create(UnicodeRanges.BasicLatin, UnicodeRanges.Cyrillic),
                    WriteIndented = true,
                };
                var newJsonText = JsonSerializer.Serialize(data, options);
    
                // Вывод на консоль.
                Console.WriteLine(newJsonText);
            }
    
            private static void Display(TriggerData data)
            {
                // Способ 1.
                foreach (var address in data.PartnerAddresses)
                {
                    // Внутри Console.WriteLine будет вызван метод ToString для
                    // экземпляра класса PartnerAddress, у которого этот метод переопределён.
                    // https://source.dot.net/#System.Private.CoreLib/TextWriter.cs,09da57c2c21a3a44
                    Console.WriteLine(address);
                }
    
                // Способ 2.
                //for (int i = 0; i < data.PartnerAddresses.Count; i++)
                //{
                //    Console.WriteLine(data.PartnerAddresses[i]);
                //}
            }
        }
    }


    TriggerData.cs
    using System.Collections.Generic;
    using System.Text.Json.Serialization;
    
    namespace ConsoleApp
    {
        public class TriggerData
        {
            [JsonPropertyName("партнерАдреса")]
            public List<PartnerAddress> PartnerAddresses { get; set; }
        }
    }


    PartnerAddress.cs
    using System.Text.Json.Serialization;
    
    namespace ConsoleApp
    {
        public class PartnerAddress
        {
            [JsonPropertyName("тип")]
            public string Type { get; set; }
    
            [JsonPropertyName("страна")]
            public string Country { get; set; }
    
            [JsonPropertyName("регион")]
            public string Region { get; set; }
    
            [JsonPropertyName("город")]
            public string City { get; set; }
    
            [JsonPropertyName("представление")]
            public string Presentation { get; set; }
    
            public override string ToString()
            {
                return $"{Type}, {Country}, {Region}, {City}, {Presentation}";
            }
        }
    }


    PartnerData.json файл должен быть сохранён в UTF-8 кодировке
    {
      "партнерАдреса": [
        {
          "тип": "тип1",
          "страна": "страна1",
          "регион": "регион1",
          "город": "город1",
          "представление": "представление1"
        },
        {
          "тип": "тип2",
          "страна": "страна2",
          "регион": "регион2",
          "город": "город2",
          "представление": "представление2"
        },
        {
          "тип": "null",
          "страна": "null",
          "регион": "null",
          "город": "null",
          "представление": "null"
        },
        {
          "тип": "тип3",
          "страна": "страна3",
          "регион": "регион3",
          "город": "город3",
          "представление": "представление3"
        }
    ]
    }


    ConsoleApp.csproj (.NET 5 проект)
    <Project Sdk="Microsoft.NET.Sdk">
    
      <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>net5</TargetFramework>
      </PropertyGroup>
    
      <ItemGroup>
        <None Update="PartnerData.json">
          <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
        </None>
      </ItemGroup>
    
    </Project>


    61284df6cbd4b767243491.png
    Ответ написан
    Комментировать
  • Как работают статические поля в C#?

    Casper-SC
    @Casper-SC
    Программист (.NET)
    Константа вычисляется статически на этапе компиляции. Константы подставляются в виде литералов в места использования этих констант. Если создать отдельную сборку только для констант, сослаться на эту сборку из основного проекта, собрать проект, то эту сборку можно будет удалить и всё будет работать, так как в основном проекте не будет ссылок на классы этой сборки, все константы будут подставлены в виде литералов. Так же изменение в сборке с константами потребует пересобрать сборку, которая использует константы.
    Здесь наглядный пример.

    readonly поле - это поле только для чтения, которое можно задать в конструкторе типа, в котором оно определено или в месте объявления поля. Если поле помечено модификатором static, то его значение можно задать только в статическом конструкторе типа, в котором оно определено или в месте объявления поля.
    Ответ написан
    Комментировать
  • Разработка веб-сайта с помощью ASP.NET. С Чего начать?

    Casper-SC
    @Casper-SC
    Программист (.NET)
    Скоро выходит книга, которая переводилась с участием .NET сообщества и нацелена на .NET 5.0.
    ASP.NET Core в действии Оригинальное название: ASP.Net Core In Action, 2nd Ed
    ISBN: 978-5-97060-550-9
    Дата выхода: сентябрь 2021 года

    Согласен с автором другого ответа, так же есть хорошая книга (лежит бумажная версия рядом со мной):
    ASP.NET Core 3 с примерами на C# для профессионалов, 8-е издание | Фримен Адам
    Ответ написан
  • Как решить быстрое закрытие программы?

    Casper-SC
    @Casper-SC
    Программист (.NET)
    Вот так можно написать класс сканер, который получает данные асинхронно. Использовать его можно таким образом в любом типе приложений. Например, в WPF приложение не будет зависать, если, скажем, запустить сканирование по клику на кнопке.

    Обрати ещё внимание на метод с Task.Factory.StartNew и параметром TaskCreationOptions.LongRunning. Для сканирования папок, думаю использовать стоит.
    using System;
    using System.Collections.Generic;
    using System.Threading.Tasks;
    
    namespace ConsoleApp
    {
        class Program
        {
            static async Task Main(string[] args)
            {
                try
                {
                    // Создаём экземпляр класса
                    var scanner = new Scanner();
                    // Вызываем асинхронный метод Scan, метод работает
                    // какое-то время, возвращает результат.
                    var data = await scanner.Scan();
                    foreach (var item in data)
                    {
                        // Выводим на консоль.
                        Console.WriteLine(item);
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex);
                }
            }
        }
    
        public class Scanner
        {
            public Task<List<string>> Scan()
            {
                return Task.Run(async () =>
                {
                    var results = new List<string>();
    
                    for (int i = 0; i < 10; i++)
                    {
                        // Делаем правильную задержку (имитация долгой работы для примера).
                        await Task.Delay(250);
                        // Собираем данные
                        results.Add(DateTimeOffset.Now.ToLocalTime().ToString());
                    }
    
                    return results;
                });
            }
    
            public async Task<List<string>> ScanVersion2()
            {
                return await Task.Factory.StartNew(async () =>
                {
                    var results = new List<string>();
    
                    for (int i = 0; i < 10; i++)
                    {
                        // Делаем правильную задержку (имитация долгой работы для примера).
                        await Task.Delay(250);
                        // Собираем данные
                        results.Add(DateTimeOffset.Now.ToLocalTime().ToString());
                    }
    
                    return results;
                }, TaskCreationOptions.LongRunning)
                    .Unwrap() // Без этого возвращается Task<List<string>>, а не List<string>
                    .ConfigureAwait(false);
            }
        }
    }


    Стоит почитать книгу "Конкурентность в C#. Асинхронное, параллельное и многопоточное программирование"
    Скриншот сделан с видео: https://youtu.be/lh8cT6qI-nA?t=1123

    612185e7a4563153795281.jpeg
    Ответ написан
    1 комментарий
  • Как создать внедряемую dll?

    Casper-SC
    @Casper-SC
    Программист (.NET)
    Документация по команде dotnet new
    В командной строке:
    dotnet new classlib -n "LibraryName" -lang "C#" -o "D:\Projects\LibraryName"

    Через Visual Studio интуитивно понятно как создать новый проект.
    Ответ написан
    Комментировать
  • Как организовать Update в window forms?

    Casper-SC
    @Casper-SC
    Программист (.NET)
    using System;
    using System.Windows.Forms;
    
    namespace WinFormsApp
    {
        public partial class MainForm : Form
        {
            private readonly Random _random;
            private readonly Timer _timer;
    
            public MainForm()
            {
                InitializeComponent();
    
                _random = new Random();
                _timer = new Timer();
                _timer.Interval = 500;
                _timer.Tick += OnTimerTick;
            }
    
            private void OnFormLoad(object sender, EventArgs e)
            {
                _timer.Start();
            }
    
            private void OnTimerTick(object sender, EventArgs e)
            {
                label.Text = _random.Next(0, 1000).ToString();
            }
        }
    }
    Ответ написан
    Комментировать
  • Почему иногда текст 2 раза пишется, а не 1 раз?

    Casper-SC
    @Casper-SC
    Программист (.NET)
    Для решения твоей проблемы тебе нужно написать твой обработчик события загрузки фрейма как показано ниже и убрать отовсюду вызов Invoke. Асинхронные методы на то и возвращают таски, чтобы в том числе можно было работать в UI потоке (основной код писать) и он не зависал.

    Если на странице несколько фреймов, то этот обработчик вызовется, когда буде загружен каждый из них
    private readonly string url = "https://kad.arbitr.ru/Card?number=";
    
    private void OnWebBrowserFrameLoadEnded(object sender, FrameLoadEndEventArgs e)
    {
        Debug.WriteLine($"{nameof(OnWebBrowserFrameLoadEnded)}. " +
                        $"Frame.IsMain: {e.Frame.IsMain.ToString()}; e.Url: {e.Url};");
    
        if (e.Frame.IsMain && e.Url.Contains(url))
        {
            Invoke((MethodInvoker)(async () =>
            {
                await UpdateData();
            }));
        }
    }


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

    ChromiumWebBrowser.FrameLoadEnd
    Ответ написан
    Комментировать
  • Наиболее исчерпывающее руководство\курс по EF?

    Casper-SC
    @Casper-SC
    Программист (.NET)
    В дополнение к предложенной документации в другом ответе можно посмотреть такую книгу:
    Entity Framework Core 2 для ASP.NET Core MVC для профессионалов | Фримен Адам (ISBN: 978-5-907114-86-9)
    Ответ написан
    Комментировать
  • Как сохранить значения переменных после перезапуска в C#?

    Casper-SC
    @Casper-SC
    Программист (.NET)
    Пример сохранения и чтения файла. Есть ещё много других способов. Для поддержки версий файла нужно внутри репозитория создать Dictionary{TKey, TValue}, где TKey - это номер версии, а TValue - сериализатор, десериализатор файла (каждый пишет и читает по своему). Далее, когда читаешь файл, то сначала читаешь его версию, а потом уже вызываешь нужную версию сериализатора и десериализатора.

    Program.cs
    using System;
    using System.Diagnostics;
    using System.IO;
    using System.Threading.Tasks;
    
    namespace GameSaveExample
    {
        class Program
        {
            static async Task Main(string[] args)
            {
                try
                {
                    var rootDirectory = Path.Combine(
                        Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
                        "AppName");
    
                    using var repository = new GameSaveRepository(rootDirectory, "SaveFile.bin");
                    Console.WriteLine("Первоначальная загрузка данных и вывод на экран:");
                    SaveData data = await repository.Load();
                    Display(data);
    
                    Console.WriteLine("Сохраняем изменённые данные и выводим на экран:");
                    data.Id += 5;
                    await repository.Save(data);
                    Display(data);
    
                    Console.WriteLine("-------------------------");
                    Console.WriteLine("Загружаем данные из файла и выводим на экран:");
                    data = await repository.Load();
                    Display(data);
    
                    Process.Start("explorer.exe", rootDirectory);
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex);
                }
            }
    
            private static void Display(SaveData data)
            {
                Console.WriteLine($"Version: {data.Version}, ID: {data.Id}");
            }
        }
    }


    GameSaveRepository.cs
    using System;
    using System.Diagnostics;
    using System.IO;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace GameSaveExample
    {
        /// <summary>
        /// Класс, который умеет сохранять данные и загружать.
        /// </summary>
        public class GameSaveRepository : IDisposable
        {
            private readonly string _rootDirectory;
            private readonly string _fileName;
            private readonly string _pathToFile;
            private readonly SemaphoreSlim _semaphore;
    
            public GameSaveRepository(string rootDirectory, string fileName)
            {
                _rootDirectory = rootDirectory;
                _fileName = fileName;
                _pathToFile = Path.Combine(_rootDirectory, fileName);
                _semaphore = new SemaphoreSlim(1);
            }
    
            public async Task<SaveData> Load()
            {
                await _semaphore.WaitAsync();
                var data = new SaveData();
                try
                {
                    await Task.Run(() =>
                    {
                        if (File.Exists(_pathToFile))
                        {
                            using var stream = File.OpenRead(_pathToFile);
                            using var reader = new BinaryReader(stream);
                            data.Version = reader.ReadInt32();
                            data.Id = reader.ReadInt32();
                        }
                    });
                    return data;
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex);
                    throw;
                }
                finally
                {
                    _semaphore.Release();
                }
            }
    
            public async Task Save(SaveData data)
            {
                await _semaphore.WaitAsync();
                try
                {
                    await Task.Run(() =>
                    {
                        if (!Directory.Exists(_rootDirectory))
                        {
                            Directory.CreateDirectory(_rootDirectory);
                        }
    
                        using var stream = File.OpenWrite(_pathToFile);
                        using var writer = new BinaryWriter(stream);
                        writer.Write(data.Version);
                        writer.Write(data.Id);
                    });
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex);
                    throw;
                }
                finally
                {
                    _semaphore.Release();
                }
            }
    
            public void Dispose()
            {
                _semaphore?.Dispose();
            }
        }
    }


    SaveData.cs
    namespace GameSaveExample
    {
        public class SaveData
        {
            /// <summary>
            /// Версия формата файла. Добавил, удалил или изменил свойство, тогда поднимаем версию.
            /// На каждую версию свой класс сериализатор-десериализатор.
            /// </summary>
            public int Version { get; set; }
    
            /// <summary>
            /// Какие-то данные.
            /// </summary>
            public int Id { get; set; }
        }
    }
    Ответ написан
    Комментировать
  • Как впихнуть компилятор в бота телеграм?

    Casper-SC
    @Casper-SC
    Программист (.NET)
    По ссылкам есть примеры кода, как компилить на лету. Как методы пихать в исходники и т.д. это другой и достаточно простой вопрос.
    Dynamically compile and run code using .NET Core 3.0
    Вот пример от Microsoft
    Cross-Platform Code Generation with Roslyn and .NE...
    Ответ написан
    Комментировать