Как динамически создать Func <T>, когда T неизвестно в C # - PullRequest
0 голосов
/ 19 января 2012

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

ConverterService converter = ...;
Task<string> originalTask = Task.Factory.FromAsync<string>(...);
Task<int> conversionTask = originalTask.ContinueWith(p => converter.Convert(typeof(string), typeof(int), p.Result));

Проблема в том, что типы неизвестны :( Мне удалось создатьОригинальная задача динамически. Вот выдержка из головы:

ConverterService converter = ...;
// dynamically calling Task.Factory.FromAsync
var originalTask = FromAsyncMethodInfo.Invoke(Task.Factory, args.ToArray());
...

// now I want to dynamically call Task<string>.ContinueWith
var conversionTask = ContinueWithMethodInfo.Invoke(originalTask, ???)

Что мне теперь делать? Я ожидаю предоставить ему Func<Task<T>, U> (что на самом деле Func<Task<string>, int> в этом примере), но как мне сгенерировать это динамически?

Чтобы все было просто, я просто хочу знать, как динамически создавать Func<T> во время выполнения, когда все, что у меня есть, - это переменная Type.динамически генерируемая альтернатива лямбде, видимая в первом блоке кода:

Task<int> conversionTask = originalTask.ContinueWith(p => converter.Convert(typeof(string), typeof(int), p.Result));

Большое спасибо заранее.

Ответы [ 4 ]

2 голосов
/ 19 января 2012

Вы можете использовать Task<object> и передавать предмет как object. Вы можете выбрать тип объекта, используя object.GetType(). Вот пример:

void Main()
{
    var conversion = new ConversionService();
    var wantedType = typeof(string);

    Task<object> originalTask = Task<object>.Factory.StartNew(
       () => { /* test impl */ return 1; }); 

    var nextTask = originalTask.ContinueWith(prev =>
       conversion.ConvertObject(prev.Result.GetType(), wantedType, prev.Result));

    var result = nextTask.Result;
    Console.WriteLine("{0} - {1}", result.GetType(), result);
}

class ConversionService
{
    public object ConvertObject(Type source, Type dest, object input)
    {
        // test impl.
        return Convert.ChangeType(input, dest);
    }
}
2 голосов
/ 19 января 2012

Я думаю, вы немного запутались в том, что именно вам нужно ... Из кода, который вы показываете, я бы сказал, что ваш Func должен будет возвращать object, и вам придется обрабатывать приведение объекта после выполнения задачи.,В дальнейшем, если ваш Func - это тот, который содержит логику для определения возвращаемого типа, вы можете вернуть составленный класс MyResult, который имеет параметры ReturnObject и ReturnType, затем после выполнения вы приведетеот ReturnObject до RetrunType объекта.

0 голосов
/ 19 января 2012

Я понял это.Сначала я создал метод с ожидаемой подписью:

public TOutput HandleTask<TTaskInput, TOutput>(TTaskInput task)

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

Работает как шарм.

0 голосов
/ 19 января 2012

Вы не можете сгенерировать Func<TIn, TOut> динамически, потому что вам нужно предоставить логику для выполнения преобразования, и пока типы не известны, вы не можете предоставить логику.

Например, есливы конвертируете int в строку, вы можете вызвать ToString (), а если вы идете в другом направлении, вы можете использовать int.TryParse ().Если у вас есть конечный набор возможных преобразований, вы можете использовать какой-то механизм для поиска во время выполнения в коллекции уже созданных делегатов, но нет способа генерировать код, который может произвольно преобразовывать значение одного типа в любой другой тип.

...