Здравствуйте, Sinclair, Вы писали:
Q>>Я бы читал: «Элвис-присваивание». S>Эмм, почему?
Родственные операторы типа ?? и ?. в C#, Kotlin и им подобных называются (традиционно/неформально) Elvis operator: «It resembles an emoticon of Elvis Presley with his quiff.»
Здравствуйте, Serginio1, Вы писали:
НС>>По той что анонимные типы были придуманы для конкретной задачи ad-hoc типов в запросах, и там мутабельность ен нужна. S>Ну анонимные типы используются не только в запросах.
Но придумали их именно для этого, и при разработке их дизайна руководствовались именно этим.
S>Для большинства задач эта мутабельность и не нужна.
Не нужна — не делай, никто не заставляет. Аргумент про таинственный Васек вредителей мягко говоря слабенький
Здравствуйте, Silver_S, Вы писали:
S_S>2) Если у тебя C# 8, и по другому работает. А у меня предыдущая версия, так работает (readonly только на struct можно ставить). В любом случае так не должно быть — ненадежная фича.
Просчитались, когда релизили 7 версию, потом исправились. Такие же защитные копии будут создаваться, например, и для ReadOnlySpan и на foreach, и в списках, да везде где есть возврат или прием аргументов толстых структур, если не озаботиться заранее, так что не только в in засада, здесь нужен соответствующий анализ и оптимизации от джита, способный все это устранить (кое-какие работы ведутся по устранению лишних клонирований, частично кое-что уже внедрено в современный Core). Хотя многое можно было бы сделать и на стороне рослина.
Здравствуйте, rameel, Вы писали:
S_S>>2) Если у тебя C# 8, и по другому работает. А у меня предыдущая версия, так работает (readonly только на struct можно ставить). В любом случае так не должно быть — ненадежная фича.
R>Просчитались, когда релизили 7 версию, потом исправились. Такие же защитные копии будут создаваться, например, и для ReadOnlySpan и на foreach, и в списках, да везде где есть возврат или прием аргументов толстых структур, если не озаботиться заранее, так что не только в in засада, здесь нужен соответствующий анализ и оптимизации от джита, способный все это устранить (кое-какие работы ведутся по устранению лишних клонирований, частично кое-что уже внедрено в современный Core). Хотя многое можно было бы сделать и на стороне рослина.
Защитную копию они могли создавать только одну, и все вызовы делать к ней. Поведение будет другое — изменения будут в ней накапливаться. Ну и нормально.
То же самое что вызов без "in" — тоже одна копия, в которой все накапливается. Сомнительно что у кого-то такое по задумке в коде — предполагает что, на каждое обращение создается копия (что изменения не накапливаются).
А в таком виде я бы не рискнул "in" использовать. Проще для "ref" вручную проверить — нет ли модификаций.
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>По той что анонимные типы были придуманы для конкретной задачи ad-hoc типов в запросах, и там мутабельность ен нужна.
А почему не нужна-то? Кто это сказал?
Очень даже бывает нужна, какой-нибудь флаг выставить в процессе обработки.
Как ты там говоришь, "сделали анонимные типы тем самым убогими", верно?
Здравствуйте, Silver_S, Вы писали:
S_S>Защитную копию они могли создавать только одну, и все вызовы делать к ней. Поведение будет другое — изменения будут в ней накапливаться. Ну и нормально.
В случае с in — да, но это к команде рослина, можно issue завести.
Здравствуйте, Silver_S, Вы писали:
S_S>То же самое что вызов без "in" — тоже одна копия, в которой все накапливается. Сомнительно что у кого-то такое по задумке в коде — предполагает что, на каждое обращение создается копия (что изменения не накапливаются).
А по поводу кода, странно, что программист in втыкает, зная, что будет копия создаваться in — он для ридонли структур или ридонли-мемберов
Здравствуйте, AlexRK, Вы писали:
НС>>По той что анонимные типы были придуманы для конкретной задачи ad-hoc типов в запросах, и там мутабельность ен нужна. ARK>А почему не нужна-то? Кто это сказал?
На тот момент в той задаче — была не нужна. В отличие от рекордов, которые снаружи совершенно обычный класс, анонимные типы штука весьма специфичная.
ARK>Очень даже бывает нужна, какой-нибудь флаг выставить в процессе обработки.
Заведи новый тип, в который включи старый отдельным свойством. let примерно так и работает
ARK>Как ты там говоришь, "сделали анонимные типы тем самым убогими", верно?
Не надо приписывать мне того, чего я не говорил, некрасиво.
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>>>По той что анонимные типы были придуманы для конкретной задачи ad-hoc типов в запросах, и там мутабельность ен нужна. ARK>>А почему не нужна-то? Кто это сказал? НС>На тот момент в той задаче — была не нужна. В отличие от рекордов, которые снаружи совершенно обычный класс, анонимные типы штука весьма специфичная.
Специфичная, но не в контексте потребности мутабельности.
ARK>>Очень даже бывает нужна, какой-нибудь флаг выставить в процессе обработки. НС>Заведи новый тип, в который включи старый отдельным свойством. let примерно так и работает
Ясное дело. Вместо изменения делается новый объект. Только вот для этого надо написать гораздо больше кода. Хммм, что-то мне это напоминает, уж не рассуждения ли о необходимости мутабельных полей в рекордах... Да не, бред какой-то.
ARK>>Как ты там говоришь, "сделали анонимные типы тем самым убогими", верно? НС>Не надо приписывать мне того, чего я не говорил, некрасиво.
Ну, раз ты считаешь рекорды без возможности мутации "убогими", то и анонимные типы ровно в той же степени "убоги".
И там, и там можно найти случаи, когда мутабельность кому-то нужна. И там, и там без нее легко можно обойтись. Твои рассуждения в равной степени применимы в обоих случаях.
Здравствуйте, AlexRK, Вы писали:
НС>>На тот момент в той задаче — была не нужна. В отличие от рекордов, которые снаружи совершенно обычный класс, анонимные типы штука весьма специфичная. ARK>Специфичная, но не в контексте потребности мутабельности.
Возможно. К анонимным типам вообще много претензий.
ARK>>>Очень даже бывает нужна, какой-нибудь флаг выставить в процессе обработки. НС>>Заведи новый тип, в который включи старый отдельным свойством. let примерно так и работает ARK>Ясное дело. Вместо изменения делается новый объект. Только вот для этого надо написать гораздо больше кода.
Если используешь query syntax — не особо.
ARK> Хммм, что-то мне это напоминает, уж не рассуждения ли о необходимости мутабельных полей в рекордах... Да не, бред какой-то.
Тебя не поймешь. Анонимные типы иммутабельны — плохо. Сделали рекордам возможность быть мутабельными — опять плохо.
ARK>Ну, раз ты считаешь рекорды без возможности мутации "убогими", то и анонимные типы ровно в той же степени "убоги".
Нет. Потому что у анонимных типов намного уже сфера применения. А рекорды это ровно те же классы в плане применимости, просто синтаксический сахар над ними, там мутабельность нужна намного сильнее.
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Тебя не поймешь. Анонимные типы иммутабельны — плохо. Сделали рекордам возможность быть мутабельными — опять плохо.
Я за максимальную иммутабельность везде. Про мутабельность это я провел параллель — если стоять на позиции "мутабельность нужна", то надо равным образом и про анонимные типы говорить.
ARK>>Ну, раз ты считаешь рекорды без возможности мутации "убогими", то и анонимные типы ровно в той же степени "убоги". НС>Нет. Потому что у анонимных типов намного уже сфера применения. А рекорды это ровно те же классы в плане применимости, просто синтаксический сахар над ними, там мутабельность нужна намного сильнее.
Будет весело, если они в RC2 мутабельность эту уберут.
Здравствуйте, AlexRK, Вы писали:
НС>>Тебя не поймешь. Анонимные типы иммутабельны — плохо. Сделали рекордам возможность быть мутабельными — опять плохо. ARK>Я за максимальную иммутабельность везде.
Это я уже понял. Но подход с мутабельными классами тоже имеет право на жизнь. И не дело проектировать мейнстрим язык исходя только из одной точки зрения на проблему.
ARK> Про мутабельность это я провел параллель — если стоять на позиции "мутабельность нужна", то надо равным образом и про анонимные типы говорить.
Я не понимаю твоего черно/белого подхода. Я тебе привел один из примеров где могут очень пригодится мутабельные рекорды. Анонимные типы в этом случае, очевидно, применить нельзя — они годны для сериализации и абсолютно бесполезны для десериализации.
Рекорды прежде всего нацелены на представление всевозможных DTO. И дизайн мутабельных DTO вполне имеет право на жизнь даже если у нас правильный сериализатор, умеющий в конструкторы, и мы не поленились в сотнях классов эти конструкторы завести.
Анонимные типы при этом заточены под представление ad-hoc типов, требующихся при запросе к БД, чтобы не плодить ORM чудовищ, генерящих select *. Для этого применения мутабельность не нужна, потому что эти типы предназначены для типизации туплов по месту их получения, и их принципиально невозможно использовать в качестве DTO.
Поэтому доказательство по аналогии, чем ты упорно занимаешься уже которое сообщение, это на самом деле никакое не доказательство.
ARK>Будет весело, если они в RC2 мутабельность эту уберут.
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Здравствуйте, artelk, Вы писали:
A>>Другой вариант: не ставить readonly на backing field. НС>Ну пипец просто. Ради того чтобы не дать сделать мутабельность надо добавить возможность мутабельности любым свойствам безусловно. Абсурд на марше.
Что не понятно-то? От рефлексии readonly тебя не спасет, а без рефлексии backing field недоступен.
Так что вполне можно было сделать так, что десериализация в иммутабельный рекорд (и класс с init-only свойствами) работала бы без проблем.
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Здравствуйте, AlexRK, Вы писали:
НС>Рекорды прежде всего нацелены на представление всевозможных DTO. И дизайн мутабельных DTO вполне имеет право на жизнь даже если у нас правильный сериализатор, умеющий в конструкторы, и мы не поленились в сотнях классов эти конструкторы завести.
Вот с этим нельзя не согласиться Вручную реализовывать IEquatable, == и т.п. и потом поддерживать их — это проблема актуальна и для мутабельных классов.
Но она актуальна и для структур.
Лучше бы остановились на модификаторе data и разрешили его применять и к классам и к струкурам, чтобы можно было, например, делать "readonly data struct".
А термин record оставили бы на будущее для чего-то более существенного — для именованных туплов с именованными полями. Причем, чтобы выбор о том, использовать под капотом класс или readonly struct для них по дефолту делался компилятором (но можно было и явно задать).
Здравствуйте, artelk, Вы писали:
A>Так что вполне можно было сделать так, что десериализация в иммутабельный рекорд (и класс с init-only свойствами) работала бы без проблем.
Нельзя. Я тебе еще раз напомню, что нормальные десериализаторы не через рефлексию работают.
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Здравствуйте, artelk, Вы писали:
A>>Так что вполне можно было сделать так, что десериализация в иммутабельный рекорд (и класс с init-only свойствами) работала бы без проблем.
НС>Нельзя. Я тебе еще раз напомню, что нормальные десериализаторы не через рефлексию работают.
А FieldInfo/PropertyInfo они откуда берут? Для кодогеренации они тоже нужны.
Кстати, вот попробовал с SRE:
public delegate void ClassFieldSetter<in T, in TValue>(T target, TValue value) where T : class;
public static class FieldSetterCreator
{
public static ClassFieldSetter<T, TValue> CreateClassFieldSetter<T, TValue>(FieldInfo field)
where T : class
{
return CreateSetter<T, TValue, ClassFieldSetter<T, TValue>>(field);
}
private static TDelegate CreateSetter<T, TValue, TDelegate>(FieldInfo field)
{
return (TDelegate)(object)CreateSetter(field, typeof(T), typeof(TValue), typeof(TDelegate));
}
private static Delegate CreateSetter(FieldInfo field, Type instanceType, Type valueType, Type delegateType)
{
var setter = new DynamicMethod("", typeof(void), new[] { instanceType, valueType }, field.DeclaringType.Module, true);
var generator = setter.GetILGenerator();
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Stfld, field);
generator.Emit(OpCodes.Ret);
return setter.CreateDelegate(delegateType);
}
}
public class Foo
{
private readonly int x;
public int X => x;
}
class Program
{
static void Main()
{
var x = typeof(Foo).GetField("x", BindingFlags.Instance | BindingFlags.NonPublic);
var setX = FieldSetterCreator.CreateClassFieldSetter<Foo, int>(x);
var foo = new Foo();
setX(foo, 42);
Console.WriteLine(foo.X); // 42
}
}
Здравствуйте, artelk, Вы писали:
A>Что не понятно-то? От рефлексии readonly тебя не спасет, а без рефлексии backing field недоступен.
Запись в readonly backing field без рефлексии и unsafe:
using System;
using System.Runtime.InteropServices;
internal class Program
{
[StructLayout(LayoutKind.Explicit)]
private struct Union
{
[FieldOffset(0)] public Foo foo;
[FieldOffset(0)] public Bar bar;
}
private class Foo
{
public int Property { get; } = 42;
}
private class Bar
{
public int field;
}
private static void Main()
{
var foo = new Foo();
Console.WriteLine(foo.Property); // 42var union = default(Union);
union.foo = foo;
union.bar.field = -42;
Console.WriteLine(foo.Property); // -42
}
}
Здравствуйте, alexzzzz, Вы писали:
A>Здравствуйте, artelk, Вы писали:
A>>Что не понятно-то? От рефлексии readonly тебя не спасет, а без рефлексии backing field недоступен. A>Запись в readonly backing field без рефлексии и unsafe: A>
[StructLayout(LayoutKind.Explicit)]
A> private struct Union
A> {
A> [FieldOffset(0)] public Foo foo;
A> [FieldOffset(0)] public Bar bar;
A> }
//...
Ээ.. почитай контекст обсуждения. Я возражал на утверждение о том, что если не ставить readonly на backing field у init-only свойств, то они якобы станут мутабельными.
Ты показал трюк еще более низкоуровневый, чем рефлексия, в котором тебе известно о лэйауте класса Foo.
Это еще один аргумент в пользу того, что readonly на backing field у init-only свойств необязателен? Аргумент не очень.
Или это возражение мне? Ну ок, надо было написать как-то так: "От рефлексии readonly тебя не спасет, а без хотя бы рефлексии backing field недоступен."
Или так: "Backing field напрямую недоступен, чтобы до него добраться нужна как минимум рефлексия, но даже от рефлексии readonly тебя уже не спасет".
Здравствуйте, artelk, Вы писали:
A>>>Что не понятно-то? От рефлексии readonly тебя не спасет, а без рефлексии backing field недоступен. A>>Запись в readonly backing field без рефлексии и unsafe: A>>
[StructLayout(LayoutKind.Explicit)]
A>> private struct Union
A>> {
A>> [FieldOffset(0)] public Foo foo;
A>> [FieldOffset(0)] public Bar bar;
A>> }
A>//...
A>
A>Ээ.. почитай контекст обсуждения. Я возражал на утверждение о том, что если не ставить readonly на backing field у init-only свойств, то они якобы станут мутабельными. A>Ты показал трюк еще более низкоуровневый, чем рефлексия, в котором тебе известно о лэйауте класса Foo. A>Это еще один аргумент в пользу того, что readonly на backing field у init-only свойств необязателен? Аргумент не очень.
Нет, это просто рефлекторная реакция на «без рефлексии backing field недоступен»