Dr. Friedrich
Ну конечно.
Крылатый
Ну конечно.
Да благословит он тебя на славный труд механикума!
Nikolay
@fvnever как создать структуру в рантайме на стеке? :D
Dr. Friedrich
@fvnever как создать структуру в рантайме на стеке? :D
А обычно у тебя структуры в рантайме на чём создаются?
Dr. Friedrich
Или ты тип рефлекшеном что ли?
Nikolay
Через Activator
Nikolay
GC0
Nikolay
Руками, вообще 0 аллокаций
Nikolay
Вот и думаю
Dr. Friedrich
об этом и многом другом читайте в нашем альманахе НИКАК
Nikolay
Блин
Nikolay
Серьёзно? :)
Dr. Friedrich
Через активатор — никак.
Dr. Friedrich
Но тебе обязательно ли активатор?
Nikolay
Не, а другие может способы есть
Nikolay
Задача - создать структуру в рантайме из типа
Nikolay
На стеке
Dr. Friedrich
Задача - создать структуру в рантайме из типа
А дальше потом с ней что делать?
Nikolay
var b = Activator.CreateInstance(typeof(MiddlewareStruct)) as IMiddleware; b.MiddlewareMethod();
Dr. Friedrich
Ну прост смотри чо, ref T я придумал, как сконструировать
Nikolay
Ой, не то
Nikolay
Вот так
Nikolay
Туда ещё заинжектить надо будет зависимости
Nikolay
Middleware для graphql
Nikolay
Ну что, есть идеи как сделать можно?
Dr. Friedrich
Там вообще как не хрен делать
Nikolay
Я напилил!
Да ладна
Nikolay
Показывай
Roman
я может ошибаюсь, но по-моему as IMiddleware все равно вызовет боксинг
Dr. Friedrich
struct MuStruct { public void MuMethod() => Console.WriteLine("MuMu"); } class Program { static unsafe void Main(string[] args) { var t = typeof(MuStruct); var x = stackalloc byte[sizeof(MuStruct)]; var s = Unsafe.AsRef<MuStruct>(&x); s.MuMethod(); } }
Dr. Friedrich
Ой, блин, с sizeof промашка, сек
Dr. Friedrich
Стоп, стопэ
Dr. Friedrich
Как аллоцировать на стеке — я показал, разве что sizeof(MuStruct) над заменить на Marshal.SizeOf(t)
Dr. Friedrich
А что ты дальше собрался с ней делать, как метод-то вызывать, если у тебя тип неизвестен в компил-тайме?
Dr. Friedrich
Это же хунта получается.
Dr. Friedrich
А туда аргументы как передать?
Ну и вообще, какие аргументы?
Dr. Friedrich
У структуры есть дефолтовый инициализатор, вот я этим и пользуюсь :)
Dr. Friedrich
Про аргументы в техническом задании ничо не было!
Nikolay
Про аргументы в техническом задании ничо не было!
Задание просто в несколько сообщений расползлось
Dr. Friedrich
Нихерасе, в структуру зависимости?
Dr. Friedrich
Мсье... знает толк, ага.
Dr. Friedrich
Давай через кодеген?
Nikolay
:D
Dr. Friedrich
Через кодеген точно можно.
Nikolay
Кодген в каком смысле?
Dr. Friedrich
Ну, экспрешеном, например.
Dr. Friedrich
Экспрешен ты осилишь составить, который делает то, что тебе нужно?
Nikolay
Ну а через него как инжектить? 🤔
Dr. Friedrich
Дак запросто же: через аргументы!
Nikolay
Но он должен быть универсальным
Nikolay
Там же тогда явно аргументы задавать придётся
Ayrat
Я думаю тут надо спросить что же ты хочешь сделать
Ayrat
Пора уже
Dr. Friedrich
struct MuStruct { public MuStruct(object arg) {} public void MuMethod() => Console.WriteLine("MuMu"); } class Program { static unsafe void Main(string[] args) { var t = typeof(MuStruct); var ctor = t.GetConstructors().Single(); var meth = t.GetMethod("MuMethod"); var dependency = new object(); var newExpr = Expression.New(ctor, Expression.Constant(dependency)); var callExpr = Expression.Call(newExpr, meth); var func = Expression.Lambda(callExpr); var deleg = (Action)func.Compile(); deleg.Invoke(); } }
Dr. Friedrich
На аллокации лучше сам проверь, но вроде как должно быть норм.
Dr. Friedrich
Я в качестве депенденси туда засунул просто обжект, но ты, очевидно, можешь анализировать аргументы конструктора и передавать что захошь — вытаскивать все аргументы из DI, например.
Dr. Friedrich
Ну и плюс, я тут довольно простецки сделал, зашив депсы прямо в тело лямбды
Dr. Friedrich
Т.е. я вызываю примерно так: var dependency = new object(); (() => new MuStruct(dependency).MuMethod())();
Dr. Friedrich
Очевидно, что аллокация структуры тут будет на стеке, а вот аллокация самой лямбды и сопутствующих деревьев выражений — в куче, и они на каждый вызов будут новые.
Dr. Friedrich
Тут уже сам доработай, чтобы лямбочку заводить по одному разу на тип и кэшировать
Dr. Friedrich
А депсы в неё передавать аргументами на каждый вызов.
Dr. Friedrich
Тогда будет zero alloc на каждый вызов (кроме первого, когда мы заводим дерево и компиляем лямбду). Кажется, ты этого хотел.
Nikolay
Хм, а так же и обычные методы получается можно быстро вызывать
Nikolay
Быстрее MethodInfo.Invoke
Dr. Friedrich
Dr. Friedrich
Если компилировать экспрешен на каждый вызов — получается медленнее, чем обычные вызовы
Dr. Friedrich
И медленнее, чем рефлекшен
Dr. Friedrich
И, наверное, даже медленнее, чем динамик.
Dr. Friedrich
Динамик сам боль-мень корректно кэширует калспоты, так что, если ты можешь свалить на динамик, то его и используй.
Dr. Friedrich
(но ты не можешь его использовать, если тип неизвестен)
Nikolay
Щас попробуем некоторые варианты
Dr. Friedrich
Некоторое дерьмо!
Dr. Friedrich
@improwks разбирается в этом дерьме.
Dr. Friedrich
Если чо, можешь в @cilchat потыкать его или меня.