Как в C# создать переменную типа значения во время выполнения?C#

Место общения программистов C#
Ответить
Anonymous
 Как в C# создать переменную типа значения во время выполнения?

Сообщение Anonymous »

Я пытаюсь реализовать такой метод:

Код: Выделить всё

(Func getFn, Action setFn) MakePair(T initialVal) {
}
Он вернет две лямбды, сгенерированные во время выполнения, которые получают и устанавливают динамически созданную переменную с использованием деревьев выражений для создания кода.
Мой Текущее решение состоит в том, чтобы динамически создавать массив типа с одним элементом и ссылаться на него:

Код: Выделить всё

(Func getFn, Action setFn) MakePair(T initialVal) {
var dynvar = Array.CreateInstance(typeof(T), 1);
Expression f = () => dynvar;
var dynref = Expression.Convert(f.Body, typeof(T).MakeArrayType());
var e0 = Expression.Constant(0);
var getBody = Expression.ArrayIndex(dynref, e0);
var setParam = Expression.Parameter(typeof(T));
var setBody = Expression.Assign(Expression.ArrayAccess(dynref, e0), setParam);

var getFn = Expression.Lambda(getBody).Compile();
var setFn = Expression.Lambda(setBody, setParam).Compile();

return (getFn, setFn);
}
Есть ли лучший способ создать переменную типа значения во время выполнения, которую можно читать/записывать, чем использовать массив?
Есть ли лучший способ ссылаться на массив, созданный во время выполнения, кроме использования лямбда-выражения для создания ссылки (поля?) для использования в ArrayIndex/

Код: Выделить всё

ArrayAccess
вызовы методов?
Избыточная справочная информация
Для тех, кому интересно: в конечном итоге это возникло в результате попытки создать что-то вроде Perl auto -оживление значений lvalue для хешей Perl.
Представьте, что у вас есть список с повторяющимися элементами и вы хотите создать словарь, который позволяет вам найти количество каждого уникального T в списке. Для подсчета можно использовать несколько строк кода (в данном случае T — это int):

Код: Выделить всё

var countDict = new Dictionary();
foreach (var n in testarray) {
countDict.TryGetValue(n, out int c);
countDict[n] = c + 1;
}
Но я хочу сделать это с помощью LINQ и хочу избежать двойной индексации countDict (интересно, что в ConcurrentDictionary для этой цели есть AddOrUpdate) ), поэтому я использую Aggregate:

Код: Выделить всё

var countDict = testarray.Aggregate(new Dictionary(), (d, n) => { ++d[n]; return d; });
Но здесь есть несколько проблем. Во-первых, словарь не создает значение для отсутствующего значения, поэтому вам нужен новый тип словаря, который автоматически создает пропущенные значения, например начальная лямбда:

Код: Выделить всё

var countDict = testarray.Aggregate(new SeedDictionary(() => Ref.Of(() => 0)), (d, n) => { var r = d[n]; ++r.Value; return d; });
Но проблема с lvalue все еще остается, поэтому вы заменяете простой счетчик int классом Ref. К сожалению, C# не может создать класс Ref первого класса C++, но использование класса, основанного на автоматическом создании лямбда-установщика из лямбда-получателя (с использованием деревьев выражений), достаточно близко. (К сожалению, C# по-прежнему не принимает ++d[n].Value;, хотя оно должно быть допустимым, поэтому вам придется создать временное значение.)
Но теперь у вас есть проблема с созданием нескольких целочисленных переменных времени выполнения для хранения счетчиков. Я расширил класс Ref, включив в него лямбду, возвращающую константу (

Код: Выделить всё

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

Подробнее здесь: https://stackoverflow.com/questions/541 ... at-runtime
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»