lundi 27 janvier 2020

C# Playing with generics, reflection and type inference

I'm doing some experiments with generic types and I'm struggling to achieve what I'm looking for. I'm actually not sure that it's even possible to do that. Here's a sample :

public class Request { }
public class RequestTest : Request { }

public class Response { }
public class ResponseTest : Response { }

public abstract class Base
{
    // some stuff
}

public abstract class WebMethodBase<TInput, TOutput> : Base
    where TInput : Request
    where TOutput : Response
{
    public abstract TOutput Execute();

    protected TInput Input { get; set; }
    protected TOutput Output { get; set; }

    public WebMethodBase(TInput input, TOutput output)
    {
        Input = input;
        Output = output;
    }
}

public class Test : WebMethodBase<RequestTest, ResponseTest>
{
    public override ResponseTest Execute()
    {
        // Do some treatment with the input
        Console.WriteLine("Test");
        return Output;
    }

    public Test(RequestTest input, ResponseTest output) : base(input, output) { }
}

public static class WebMethodBaseHelper
{
    public static WebMethodBase<TInput, TOutput> Create<TInput, TOutput>(TInput input, TOutput output)
        where TInput : Request
        where TOutput : Response    
    {
        Type baseType = typeof(WebMethodBase<TInput, TOutput>);
        Type childType = baseType.Assembly.GetTypes().Where((t) => baseType.IsAssignableFrom(t) && t.IsClass).FirstOrDefault();
        var constructor = childType.GetConstructor(new Type[] { typeof(TInput), typeof(TOutput) });
        return (WebMethodBase<TInput, TOutput>)constructor.Invoke(new Object[] {input, output});
}

class Program
{
    private static TOutput Execute<TInput, TOutput>(TInput input, TOutput output)
        where TInput : Request
        where TOutput : Response 
    {
        WebMethodBase<TInput, TOutput> webMethod = WebMethodBaseHelper.Create(input, output);
        return webMethod.Execute();
    }

    private static ResponseTest Run(RequestTest request)
    {
        return Execute(request, new ResponseTest());
    }

    static void main(string[] args)
    {
        ResponseTest result = Run(new RequestTest());
    }
}

This sample is working but it's unclear which implementation of WebMethodBase<> is instanciated. What I'd like to achieve is to modify the Execute function to be able to call it this way inside the Run function :

return Execute<Test>(request);

Since the Test class is inheriting WebMethodBase<> I guess somehow we should be able to retrieve the generic types and make the whole function generic as well, but I'm not really sure that this is something possible. I tried a lot of different ways already and this is the closest implementation I was able to get from what I want.

Any help or explanation of why this is not possible would be much appreciated.

Thanks





Aucun commentaire:

Enregistrer un commentaire