Comments 172
Microsoft уже сами депрецировали не cross platform версию .Net. Сейчас большинство .Net приложений или уже на linux, или переходят, так как это отличный способ экономии.
Это, кстати, крайне удобно для разработчиков. В то время как джависты с трудом «продают» переход со старых версий Spring, .Net разработчикам достаточно показать как дорого стоит виндовый сервер и… рефакторинг продан:)
> Десктоп приложения на нем писать можно только под мелкомягких
А разве десктоп кому-то сейчас нужен? Сейчас разработка это или бек, или веб фронт, или мобилки, или игры.
>… глючном юнити
А можно рассказать про глючность юнити? А то у читателей может возникнуть ложное ощущение, что в Unreal Engine, как будто, глюков меньше.
А разве десктоп кому-то сейчас нужен?
Да.
Сейчас все в в вебе. Сегодня популярные десктоп, приложения можно по пальцам пересчитать: web-браузеры, IDE, Office. Я больше не смог вспомнить ни одного desktop приложения не из этих категорий, которое бы использовал за последний год.
"Не будет ни театров, ни кино, ни книг. Одно сплошное телевидение!" © к/ф "Москва слезам не верит".
Вы не первый.
2. Остальные редакторы, не попавшие в п. 1: текстовые, научные, музыкальные, туда же относятся, например, слайсеры для 3д принтеров.
3. Различные корпоративные приложения (erp, crm) — далеко не все в вебе.
4. Игоры.
5. Всевозможный геймдев-тулинг, включая мобильный геймдев, запускается на десктопе онли.
6. Специализированные приложения для конкретного железа — их целый пласт, от прошивальщиков ECU до контроллеров больших станков.
7. Клиенты видеонаблюдения. Браузеры пока не умеют в h265.
Это то, что навскидку вспомнил.
.net уже давно как кроссплатформенный, а заморачиваться десктоп приложениями под никсы, зачем и для кого? Уже под вондовс десктоп давно как умер, а вы никсы хотите.
github.com/AvaloniaUI/Avalonia
github.com/unoplatform/uno
P.S сейчас посмотрел доку, она стала намного лучше, появились туториалы. Вообще проект очень многообещающий, желаю ему удачи, но пока что это не совсем пригодно для продакшена.
2) Avalonia UI
2) имхо основной упор таких технологий как Java и .NET сейчас именно в вебе. Xamarin нужен в основном если очень важно иметь кодовую базу на одном ЯП.
Интерфейс должен выглядеть нативно везде, свинг этому не соответствует. Qt соответствует, но он не про Яву совсем.
Нативно выглядящие фрэймворки для шарпа я приложил в другом комментарии:
github.com/AvaloniaUI/Avalonia
github.com/unoplatform/uno
Так что это проблема из прошлого.
Про Авалонию и её определённую сырость я спорить не могу, пилят вовсю, а что не так с Уно?
Не смешите меня. Мы например делаем автоматические и полуавтоматические производственные линии и для наших клиентов «облако» это ругательное слово. Сейчас никто в здравом уме не будет пихать управление подобными вещами в облако. Там даже обычно доступа к интернету нет :)
Да я и не смешу. То, что десктопная разработка в B2B становится нишевой это неоспоримая реальность, чем дальше, тем меньше её будет, и ориентироваться на нишу при разработке массового инструмента нецелесообразно.
insights.dice.com/2020/03/04/desktop-development-dead-still-worth-it
Conclusion: Desktop (Barely) Hanging On
Если честно то после того как тестовые приложения начали глючить на наших тестовых «экзотах», то мы даже и разбираться не стали. Может потом ещё раз попробуем.
Когда это было и на какой версии?
И да, чистый десктоп всё больше становится нишей. Но скорости там совсем не космические…
Какие бы скорости ни были, тренд очевиден, будущее не за десктопом, и прицельно под него разрабатывать на разные платформы это не очень умно с точки зрения бизнеса, особенно с учётом, того, что уже есть сторонние продукты, реализующие кроссплатформенный десктоп.
Было это года полтора-два назад. И поскольку занимался этим не я лично, то детали сейчас дать не могу. Но если действительно интересно, то могу поспрашивать.
Тогда у Уно ещё версии 2.0 не было, сейчас актуальна третья ветка, даже с поддержкой и обучением:
platform.uno/training
blogs.windows.com/windowsdeveloper/2020/05/19/introducing-winui-3-preview-1
github.com/dotnet/maui#xamarinforms-vs-net-maui
Какие бы скорости ни были, тренд очевиден, будущее не за десктопом, и прицельно под него разрабатывать на разные платформы это не очень умно с точки зрения бизнеса, особенно с учётом, того, что уже есть сторонние продукты, реализующие кроссплатформенный десктоп.
скоро в рф будет чебурнет и вы будете сидеть в каком-н российском облаке. Или БЕЗ облаков.
свинг этому не соответствует
Никто не запрещает задать одинаковый LookAndFeel для всех систем или создать свой.
- Высокий порог входа, по сравнению с php или go
- Зарплаты на 10% ниже чем у Java разработчиков сравнимой компетенции
- До сих пор есть «особенные» разработчики, считающие что C# это только Windows или только формочки
- Есть несколько языковых конструкции (например поддержка динамической типизации вместе со статической) которые не нужны (хотя тот же dynamic замечательно подходит для прототипирования)
- Не возникают так часто проблемы с heap при работе с большим объемом данных (так как есть отдельный дефрагментируемый heap для больших объектов), но вот конфигурируемости GC, что есть в java, увы нет. Как и внятных альтернативам дефоллтному GC
- AOP есть, но не популярен
- Есть только один внятный фреймворк для мутационного тестирования
- Интерация со Apache Spark тольк очерез API (как сделано в python), т.е. нет возможность вклинивать свой код в ноды, как можно в JVM ориентированных языках
- ML в зачаточном состоянии. Но это если мы не говорим о SAAS. В плане интеграции с ML SAAS решений все ок (а это и нужно в 90% случаев :) )
- Кросс платформ для мобилок очень мощный (так как есть прямой доступ к нативным API), то требует высокой квалификации (так как есть прямой доступ к нативным API)
- Если говорить о Unity, то проблема не в «глюках», а в банальных вещах: GC (в Unity он «свой») и комплируемости языка (очень бесит что, по сравнению с Godot, необходимо перезапускать проект (и перепроходит уровень) ради написания одной строчки кода)
- .wasm фреймворк blazor неплох, но пока недостаточно mature
- Интеграция с anaconda есть… но этого недостаточно
Т.е. если у вас есть задачи, которые я описал выше (ML, Data Science, Spark, Big Data), то C# тут действительно не очень хорошо подходит
После шарпа, зайти в php с его синтаксисом ($, ->) и слабо развитым инструментарием, было больно. Так что тут еще неизвестно где порог входа (боли) выше :)
В java зп выше, ну так это за вредность доплачивают.
По поводу dynamic, так по мимо него есть еще и goto, но это не проблемы языка.
На java написано много всякого распределенного и высоконагруженного. См spark, hadoop, kafka, lucene, elasticsearch. На C#/.NET ничего такого практически нет (RavenDB, что ещё?)
Как результат, на C# много вакансий клепать круды и формочки, а на java больше интересных вариантов.
На java больше интересных вариантов.
Если смотреть вакансии по России — кроме банков и страховщиков много контор, которым java кодеры нужны? Я вот только jetbrains могу вспомнить. Так что насчет интересности я бы поспорил.
Одноклассники и Яндекс.
У первых хватает всякого веселого самописного и работы в open source проектах, помимо всей соцсети.
Во втором есть Маркет, Облако и разные другие веселые ребята.
А еще есть ALM(с плагином для JIRA), биоинформатики, Wrike со своей альтернативой JIRA, Exactpro со своими инструментами автоматизации тестирования, куча финтех проектов, Почта России(сам в афиге), разные аутсорсеры и консультанты и далее, далее, далее…
Это те компании, в которые меня пытались схантить, либо в которых я работал. Ну и это Питер, в основном. На мой взгляд — работа есть.
На Java когда то даже геномный ассемблер писали.
Если начинать сейчас средний типовой проект на микросервисах с бэком, фронтом + мобайл ну кто на джаве его будет строить.
Не переучиваться же им на C# только ради возможности построить очередной типовой проект, которые они уже строили не раз на известном им стеке.
Да и Kotlin + JVM на мой взгляд удобнее для таких проектов, чем C# + .Net. Как минимум наличием нормальной IDE под Linux.
Насколько я помню, Rider по возможностям не дотягивает ни до IntelliJ IDEA ни до Visual Studio.
Если я не прав — что ж, голову пеплом(в прямом смысл) я умудрился посыпать еще позавчера :)
Про саму IDEA судить особо не могу, но она славится своими рефакторингами, которых у Rider тоже есть богато.
Единственное ограничение, с которым я сталкивался на практике — нет поддержки шаблонов T4, которые любят в легаси проектах.
А какая поддержка нужна? Код сгенерить можно, подсветка есть, хоть и частичная.
Насколько я помню, решарпер перестали прикручивать несколько лет назад. Толи конфликтовал он с новыми возможностями студии, толи перестал быть нужным из-за них.
Но это лишь выжимка из дошедших до меня слухов.
Для меня Rider по возможностям как минимум не хуже студии. Насчет IDEA не могу сказать точно, но на первый взгляд они примерно одинаково мощные, хотя сравнивать их не совсем корректно, так как все же на разные языки ориентированы.
Rider и IDEA — это одна и та же IDE, заточенная под разные языки (как и все прочие IDE от жетбрейнс). Пользуюсь и тем и другим ежедневно, под Linux. Возможности примерно одинаковые.
По поводу dynamic, так по мимо него есть еще и goto, но это не проблемы языка
.
Начинающие программисты говорят, что goto — зло.
Продвинутые — пытаются замаскировать goto под break, throw, return…
Просветленные — молчат и улыбаются когда пишут goto.
тот же выход из вложенных циклов куда проще через goto, чем флаги. И хреновый код это не проблема языка. Скорее, использование множества флагов вместо goto это хреновый код.
тот же выход из вложенных циклов куда проще через goto, чем флаги
А точно не через break по метке?
Есть несколько языковых конструкции (например поддержка динамической типизации вместе со статической) которые не нужны (хотя тот же dynamic замечательно подходит для прототипирования)
Как-то странно записывать в минусы языка его фичи, которые не обязательно использовать.
Есть несколько языковых конструкции (например поддержка динамической типизации вместе со статической) которые не нужныЕсть некоторые вещи, которые без динамической типизации не реализуются
github.com/NightmareZ/PropertyProxy
Для таких случаев придумали интерфейсы.
А ловить ошибки доступа в рантайме — что, не гемморой?
Плюс такой подход нарушает DIP. Плюс такой подход ломается когда у вас есть два потребителя, которым требуются разные API.
Я делал простой 2D редактор, где по холсту можно было таскать компоненты. Каждый компонент задаётся классом, количество компонентов и их типов заранее неизвестно. У каждого компонента (класса) есть набор свойств, увсех разное. Мне нужно было отображать эти свойства в некотором гриде.
Как должен работать грид. Ты задаёшь свойствам своего класса специальный аттрибут. Затем можешь объект этого класса передать в этот грид и он отобразит все те свойства, которые ты аттрибутом пометил, а другие — не отобразит.
Всё бы было хорошо, но грид не работал, как надо, и отображал все свойства объекта, даже те, которые не нужно. Можно было, конечно, использовать другой грид или ещё как-то поступить по-умному, но я вышел из ситуации таким вот образом: создал генератор прокси-классов, которые пробрасывали нужные свойства, помеченые атрибутами.
Вот, теперь задача начинает вырисовываться, и она отличается от того, что было написано изначально.
Во-первых, вам тут нужен класс для передачи в чужой код, который будет обращаться к нему через отражение (рефлексию). Вам для этой задачи нет необходимости обращаться к этому классу самостоятельно через dynamic, задача решается без него!
Во-вторых, вполне возможно, что вам на самом деле был нужен метод TypeDescriptor.AddProvider. Или можно вовсе сделать особый класс, основанный на массиве настроек...
Да, вот вам для примера код с которого можно начать:
[TypeDescriptionProvider(typeof(PropertyProxyTypeDescriptionProvider))]
public sealed class PropertyProxy
{
public PropertyProxy(object obj, IReadOnlyCollection<string> properties)
{
Object = obj;
Properties = properties;
}
public object Object { get; }
public IReadOnlyCollection<string> Properties { get; }
}
public sealed class PropertyProxyTypeDescriptionProvider : TypeDescriptionProvider
{
public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
{
if (instance is PropertyProxy pp)
return new TD(pp);
return base.GetTypeDescriptor(objectType, instance);
}
private sealed class TD : CustomTypeDescriptor
{
private readonly PropertyProxy pp;
public TD(PropertyProxy pp)
{
this.pp = pp;
}
public override PropertyDescriptorCollection GetProperties() => GetProperties(null);
public override PropertyDescriptorCollection GetProperties(Attribute[] attributes)
{
var result = TypeDescriptor.GetProperties(pp.Object, attributes)
.Cast<PropertyDescriptor>()
.Where(prop => pp.Properties.Contains(prop.Name))
.Select(prop => new PD(prop))
.ToArray<PropertyDescriptor>();
return new PropertyDescriptorCollection(result);
}
}
private sealed class PD : PropertyDescriptor
{
private readonly PropertyDescriptor inner;
private EventHandler onValueChanged = null, innerValueChanged = null;
public PD(PropertyDescriptor inner) : base(inner)
{
this.inner = inner;
}
public override Type ComponentType => typeof(PropertyProxy);
public override bool IsReadOnly => inner.IsReadOnly;
public override Type PropertyType => inner.PropertyType;
public override TypeConverter Converter => inner.Converter;
private object GetObject(object component) => ((PropertyProxy)component)?.Object;
public override bool CanResetValue(object component) => inner.CanResetValue(GetObject(component));
public override object GetValue(object component) => inner.GetValue(GetObject(component));
public override void ResetValue(object component) => inner.ResetValue(GetObject(component));
public override void SetValue(object component, object value) => inner.SetValue(GetObject(component), value);
public override bool ShouldSerializeValue(object component) => inner.ShouldSerializeValue(GetObject(component));
private EventHandler MakeInnerValueChanged(object component)
{
if (innerValueChanged == null)
innerValueChanged = (_, args) => onValueChanged?.Invoke(component, args);
return innerValueChanged;
}
public override void AddValueChanged(object component, EventHandler handler)
{
if (onValueChanged == null)
inner.AddValueChanged(GetObject(component), MakeInnerValueChanged(component));
onValueChanged += handler;
}
public override void RemoveValueChanged(object component, EventHandler handler)
{
onValueChanged -= handler;
if (onValueChanged == null)
inner.RemoveValueChanged(GetObject(component), MakeInnerValueChanged(component));
}
}
}
Работоспособность не проверял, но после исправления каких-нибудь глупых NRE должно заработать. Просто передаём вашему гриду new PropertyProxy(realObject, new HashSet<string>(список свойств))
, и он должен отобразить для редактирования указанные свойства (если это адекватный грид, уважающий ComponentModel).
Как видно, ни dynamic, ни кодогенерации, ни даже открытой рефлексии для решения задачи не понадобилось.
(хотя тот же dynamic замечательно подходит для прототипирования)
Никогда не мог понять подобных заявлений. Каким образом это может облегчать прототипирование хоть как-то? Или это я не умею на питоне динамиках писать?
Мне кажется, в плане Unity не стоит вообще обновляться на на LTS релизы. Разработчики пилят сейчас очень много новых (и реально крутых) фич, что с учетом размеры команды, не позволяет им с первого раза выкатывать нормальную версию. В принипе, похожая ситуация была в свое время с докером, когда x.0 версией нельзя было пользоваться.
> Парадигма поиска объектов по их текстовому имени
А кто требует этим пользоваться, можно же искать по тегу? В unity есть еще масса проблемных вещей, которые не стоит юзать.
> Проваливание гейм объектов через стандартные коллайдеры
А можно линку? У меня были похожие проблемы, но только если я двигал что-то в Update, а не в FixedUpdate. Но похоже тут другая проблема…
stackoverflow.com/questions/44266691/collision-detection-for-fast-moving-game-object-in-unity
Поменяйте тип collision detection на continuous для вашего коллайдера, и будет вам счастье. Это не специфично для Юнити, все физические движки так работают, я не понимаю, что там было обсуждать несколько лет.
Статья ради статьи?
Шапрпповый код при компиляции превращается в промежуточный язык, который выполняется JIT-компилятором на клиентской машине — в этом есть свои преимущества, но такой принцип работы не оставляет шансов писать настолько же быстрый код, как на плюсах или голанге. Но C# все ещё достаточно быстрый в своей категории
Просто оставлю это здесь: https://benchmarksgame-team.pages.debian.net/benchmarksgame/fastest/go-csharpcore.html
C# почти на всех бенчмарках бьёт Go по скорости. Могли бы потрудиться посмотреть их.
А вот где действительно есть просадка, так это во времени запуска. Но тут лучше не go выбирать, а node.js, так как холодный старт объективно выше в интерпретируемых языках.
С другой стороны… а в каких случаях вам нужен именно быстрых холодный старт?
С другой стороны… а в каких случаях вам нужен именно быстрых холодный старт?
Serverless. Там это бывает важно. Хотя облака с этим борятся. Амазон, например, в прошлом году запилил Provisioned Concurrency, который правда денег стоит.
Так же была одна задача, когда генерили тонну инстансов на пару секунд. И там JIT был оченьвреден и пришлось использоват другой подход.
Действительно странная логика автора: c чего это JIT может быть медленее AOT?
С того, что у JIT, в отличие от AOT, весьма небольшое время для применений оптимизаций, и потому некоторые оптимизации он просто не в состоянии провести в принципе?
Можно сначала скомпилировать быстро а потом при необходимости в фоне перекомпилировать уже с оптимизациями.
https://github.com/dotnet/runtime/blob/master/docs/design/features/tiered-compilation.md
C# кажется лучшим языком общего назначения на данный момент:
- Лучший тулинг
- Лучшая стандартная библиотека
- Лучшая документация
- Перформанс близок к нативному коду
- Высокая скорость разработки
- Нормальный асинк
- LINQ
- Низкоуровневые возможности, лёгкий интероп с нативным кодом
Kotlin наступает на пятки, но пока ещё недостаточно популярен.
В дотнете на все есть практики, и все им следуют
Да, и это прекрасно. Взять ту же асинхронщину. Да, тема сложная, но всё стандартизировано, расписано в доках, изучи и будет хорошо. В Java, к примеру, полный бардак и зоопарк, в каждой либе свои Future, культура асинхронного кода отсутствует, далеко не все даже "синьёры" знают, как правильно с этим всем работать.
habr.com/en/post/520114/#comment_22130682
Возникает ощущение, что большинство не .net разработчиков предпочитает не задумываться о существовании C#/.Net. И как результат, страдают. Невежество оно такое… поражает в первую очередь невежду.
А как же CompletableFuture в Java?
Проблема в том, что CompletableFuture
— это аналог TaskCompletionSource
, возвращать его из public API не айс, это нарушает инкапсуляцию — кто угодно снаружи может вызвать complete()
. Казалось бы, можно возвращать CompletionStage
, но оно не реализует Future
. Более того, у CompletionStage
есть toCompletableFuture()
, что возвращает нас к изначальной проблеме. Всё это выглядит как ошибка проектирования.
Вышесказанное, а так же исторические причины, приводит к тому, что многие популярные либы возвращают свои собственные фьючи (см Netty, Lettuce). Можно представить, как здорово смотрятся 3 разных фьючи в рамках одного проекта.
Мне интересно почему новые проекты не стартуют массово именно на C#, почему люди, которые принимают решения (технологии + бюджет) все еще не смотрят на .net по дефолту
- Перформанс близок к нативному коду
- LINQ
Вот эти вещи довольно плохо сочетаются.
А что не так с LINQ?
То, что он плохо оптимизируется, причём чисто в силу дизайна, основанном на стирании типов.
Сам интерфейс LINQ статически типизирован
Да в том-то и дело, что не очень. Что возвращает Where? Where возвращает IEnumerable<TSource>. Что возвращает Skip? Снова IEnumerable<TSource>. А что возвращает Select? IEnumerable<TResult>. Каждый из этих методов возвращает вполне конкретный тип, но в силу того, что тип объявлен как IEnumerable<T>
, эта информация теряется, тип деградирует до интерфейса, и компилятору приходится выяснять, какой именно это тип на самом деле, чтобы модно было заинлайнить методы.
Также все методы IEnumerable также принимают экземпляр интерфейса. Казалось бы, что мешает написать сигнатуру навроде
public static IEnumerable<TSource> Where<TSourceEnumerable, TSource> (this TSourceEnumerable source, Func<TSource,bool> predicate) where TSourceEnumerable: IEnumerable<TSource>;
Но нет, мы будем принимать именно интерфейс и забывать исходный тип. И плевать, что мог быть структурой — мы всё равно сделаем сигнатуру, которая всегда будет требовать боксинга.
И в итоге мы имеем, что при написании проекта на C# всегда нужно выбирать между удобством LINQ и производительностью циклов.
что мешает написать сигнатуру навроде
Передача структуры в метод по значению (копирование).
И плевать, что мог быть структурой — мы всё равно сделаем сигнатуру, которая всегда будет требовать боксинга.
Все стандартные коллекции (включая массивы) .NET — референсные типы. Кейс с коллекциями-значениями имеет право на существование, но преувеличивать их значение в типичных сценариях использования C#, имхо, не стоит.
Работу ты все равно найдешь только бекендером — других вакансий тупо не бывает.
Слишком громкая фраза. Может быть большинство вакансий для бекендеров, но существуют и другие сферы.
Корная либа
Май айз а блидин…
промежуточный язык, который выполняется JIT-компилятором на клиентской машине
У вас почему-то слова «выполняется» и «компилятором» находятся в одной строке.
Соль в том, что jit-компиляция — это устоявшийся термин. Вам следовало спорить чем оно является и чем не является 17 лет назад.
И да, JIT-компилятор именно что компилирует. Только не всю программу целиком, а отдельные методы.
Какая-то совершенно сумбурная статья. Как из неё можно понять, где используется платформа .Net, какие у неё в этих нишах конкуренты? Особенности самого языка из статьи может понять только ветеран боёв в комментариях, а не свежеиспечённый программист.
Даже какой-нибудь IEEE Spectrum, несмотря на спорные результаты, полезнее такой статьи. Там хоть какие-то критерии есть.
А так, это среда общего назначения, очень общего. Игры, игровые движки, десктоп, бэкэнд, в принципе даже высоконагруженные приложения и в какой-то мере ML.
Ни в чём из этого, кроме десктопа, язык не обладает киллер-фичами, но он просто неплох во всём.
Мне немного стыдно, когда я вижу код минимально рабочей программы на C#Скоро в C# 9:
using System;
Console.WriteLine("Hello World!");
типа хадуп, спарк например и его части.
Есть ли аналоги-конкуренты чего-то из экосистемы Хадуп написанные на шарпе?
если, например, хочу в перспективе удаленно работать на буржуев?
и с какой его частью стоит связываться на перспективу — десктоп или web, бэк или фронт, Blazor или ASP, ковырять ли интеграцию приложений с Azure?
хочу в перспективе удаленно работать на буржуев
Если это — единственная цель, то ответ — нет. Лучше учить Javascript, вакансий намного больше.
Но если есть цель стать хорошим разрабом, то C# — один из лучших вариантов для обучения, потому что даёт возможность попробовать себя во всех областях (бэк, фронт, игры, мобилки), и даёт понимание разнообразных концепций и подходов (асинхронщина, функциональщина, итд). После опыта с шарпом несложно переходить на другие языки. А вот с жаваскрипта перейти на что-то другое будет посложнее.
Самое дурацкое — очень легко стать шарповой боевой единицей, но момент, как работает твой код — наступит оооочень не скоро. В платформе, принципах её работы — масса нюансов, которые по щелчку не выучатся.Прям интересно стало(без сарказма). Можете привести пример? И, если можно, то посоветуйте литературу какую-нибудь.
И, если можно, то посоветуйте литературу какую-нибудь.
clr via c#, исходники платформы в репозиториях github.com/dotnet
масса нюансов, которые по щелчку не выучатся
Шарпы — популярны
Исходя из этого пункта не понятно зачем нужно, т.к. есть много более популярных языков.
C# — мощный язык с кучей возможностей
Если вам скучно можете найти в языке ещё одно специальное решение для особого случая, что бы ваши коллеги/наследники, подольше разбиралить. А что вы хотели программирование — это не просто, знали куда шли.)
Дотнет — для ентерпрайза
Описали почти любой ЯП общего назначения.
# Стоит ли связываться с C#