Как стать автором
Обновить
29
Карма
0
Рейтинг

Пользователь

typeof(T) vs. TypeOf⟨T⟩

Пока не отработал конструктор объект никуда не может быть добавлен, поскольку на него ещё нигде нет внешних ссылок.

typeof(T) vs. TypeOf⟨T⟩

Выглядит так, что в худшем случае мы можем лишь потерять элемент, уже находящийся в словаре, что приведёт к его пересозданию извне, но если элемент по ключу найден, то чтение безопасно, поскольку индеск в массиве за ним закрепляется навсегда.

typeof(T) vs. TypeOf⟨T⟩

Поясните…

Ссылка на экземпляр объекта становится в первую очередь доступной в конструкторе, а потом уже вовне (если мы её не передали куда-то до завершения выполнения конструктора из самого конструктора). Исключение составляет случай создания объекта без вызова конструктора FormatterServices.GetUninitializedObject. Это насколько мне известно.

typeof(T) vs. TypeOf⟨T⟩

Это, конечно, интересный момент, но по беглому изучению кода выглядит так, что entries при добавлении новых элементов может лишь увеличиваться в размере, а перекладка элементов в новый массив происходит без смешивания, через Array.Copy, поэтому даже старый индекс будет валиден в случае нового массива, вопрос остаётся открытым…

typeof(T) vs. TypeOf⟨T⟩

Повторное чтение происходит по тому же ключу, что и при первой неудачной попытке.

typeof(T) vs. TypeOf⟨T⟩

Обменяться-то они могут, но по хэш-коду вычисляется номер «корзины» (связного списка), а поиск в списке уже идёт по строгой эквивалентности ключа, поэтому в худшем случае элемент может не найтись, хотя он в словаре присутствует (и-то мне видится это крайне маловероятным событием, если вообще возможным).

typeof(T) vs. TypeOf⟨T⟩

Заглядывал когда-то давно. Конечно, могу ошибаться, но на вскидку такое маловероятно, поскольку если не найдено соответствия по ключу, то с чего бы возвращать дугое значение. Теоретически, может быть такое, что ключ уже попал в словарь, а значение пока ещё не присвоилось, но тогда хотя бы дефолтный null вернуться должен.

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

typeof(T) vs. TypeOf⟨T⟩

Понимаю, конечно. Но в данном решении атомарность и не требуется за счёт повторного чтения под локом.

С непривычки да, но как бы должно работать, поскольку компилятор обеспечивает однозначный и потокобезопасный контекст блокировки.

typeof(T) vs. TypeOf⟨T⟩

lock и Dictionary уже готовые, поэтому использую их по максимуму. :)
За надёжность не ручаюсь, но выглядит работоспособно, мне было бы интересно словить ошибку в такой комбинации, если она возможна.

Для большей уверенности, конечно, можно использовать ConcurrentDictionary, но его производительность я не измерял собственноручно.

typeof(T) vs. TypeOf⟨T⟩

Внешняя ссылка на экземпляр класса RipeType может появится только после выполнения конструктора, в каком бы потоке мы ни выполняли оператор new. Исключение составляет лишь случай вроде
    class AnyClass
    {
        public static AnyClass Instance;

        public AnyClass()
        {
            Instance = this;
            /* ... */
        }
    }

Но это не наша ситуация, поэтому вариант с недоинициализированным RipeType отпадает.

По логике вещей, при чтении структура словаря не может быть нарушена, даже если оно идёт из разных потоков. При параллельной записи тоже, поскольку есть lock. Остаётся лишь случай чтения в момент записи… Мне думается, что словарь не бросит исключение от такого, а если вдруг чтение произошло до момента вставки только что созданного экземпляра и вернулся null, то мы направляемся в lock и дожидаемся завершения вставки, после чего повторяем чтение и получаем уже созданный экземпляр.

typeof(T) vs. TypeOf⟨T⟩

Насколько понял из беглого ознакомления с type traits, идеи в основе схожие, но раньше мне не попадалось подобного рода оптимизаций на C#, разве что кэширование в переменную встречал (вместо многократного повторения вызова typeof(T).GetSomething()).

Статический же TypeOf позволяет несколько обобщить подход, например, реализовать быстрый доступ к информации о типе из разных частей приложения, что довольно удобно, на мой взгляд.

typeof(T) vs. TypeOf⟨T⟩

Можно и ConcurrentDictionary использовать, если нужно.

По началу у меня самого были подозрения насчёт такого решения, но при более детальном анализе я пришёл к выводу, что оно довольно безопасное. Буду признателен, если вы всё же укажете на возможный сценарий, приводящий к ошибке… Мне самому интересно о нём узнать, если он существует.
Да и завязываться на то что компилятор закеширует передаваемый в Lock.Invoke делегат тоже не стоит...

Если в разных потоках создать два делегата от одного метода, то они будут равны, поэтому lock сработает корректно.

typeof(T) vs. TypeOf⟨T⟩

Вот еще заметил. Судя по бенчмарку, GetRipeType всегда медленнее чем простой GetType. Так зачем оно нужно?

Зависит от сценария использования. Если получается единожды закэшировать информацию о типе объекта, то потом быстрее её брать из RipeType, чем из Type

static RipeType AnyRipeType = anyObject.GetRipeType();

static void AnyPerformanceCriticalMethod()
{
	/* ... using of AnyRipeType ... */
}

В каждом конкретном случае нужно выбирать более оптимальное решение, чтобы достичь максимальной производительности, поскольку есть различия даже на разных CLR.

Исправлять ли unexpected behavior в C# 7 или оставить как есть, усложнив синтаксис языка для компенсации?

Druu
И да, я считаю, что
public static double CalculateSquare(
    this Shape shape) => shape.Match
(
    (Line _) => 0,
    (Circle c) => Math.PI * c.Radius * c.Radius,
    (Rectangle r) => r.Width * r.Height,
    () => double.NaN
);

Выглядит сейчас получше, чем обычный switch.

Исправлять ли unexpected behavior в C# 7 или оставить как есть, усложнив синтаксис языка для компенсации?

Мой код соответствует моим понятиям о математической красоте.

Исправлять ли unexpected behavior в C# 7 или оставить как есть, усложнив синтаксис языка для компенсации?

А для меня это и есть то самое начало, за которое мне нравится программирование, поэтому к ней стремлюсь в любом языке.

Исправлять ли unexpected behavior в C# 7 или оставить как есть, усложнив синтаксис языка для компенсации?

Тогда уж вводите оператор правостороннего присваивания для полной математической красоты
var x = SomeFunction(); //pure
SomeFunction() to var x; //pure

и повторяйте все ваши манипуляции с ним…

Исправлять ли unexpected behavior в C# 7 или оставить как есть, усложнив синтаксис языка для компенсации?

default var
case var
case object
Так себе аргумент с визуальной сложностью.

Во-вторых, вывод типа никуда не делся.
В-третьих, добавилось неочевидное поведение с null.

Информация

В рейтинге
5,779-й
Зарегистрирован
Активность