C# 使用泛型、反射和类型推断



我正在对泛型类型进行一些实验,我正在努力实现我想要的东西。我实际上不确定是否有可能做到这一点。下面是一个示例:

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());
}
}

此示例正在运行,但对于任何阅读该代码的人来说,都不清楚在调用Execute方法时WebMethodBase<>的实现是实例化的。我想实现的是修改Execute方法,以便能够在Run方法中以这种方式调用它:

return Execute<Test>(request);

由于Test类继承了WebMethodBase<>我想我们应该以某种方式能够检索泛型类型并使整个函数也泛型,但我不确定这是否可能。我已经尝试了很多不同的方法,这是我能够从我想要的东西中获得的最接近的实现。

任何帮助实现这一目标或解释为什么这是不可能的,将不胜感激。

谢谢


编辑

我可以通过以下条件得到我想要的东西:

private static TOutput Execute<TMethod, TInput, TOutput>(TInput input)
where TMethod : WebMethodBase<TInput, TOutput>
where TInput : Request
where TOutput : Response, new()
{
TOutput output = new TOutput();
var constructor = typeof(TMethod).GetConstructor(new Type[] { typeof(TInput), typeof(TOutput) });
TMethod instance = (TMethod)constructor.Invoke(new Object[] { input, output });
return instance.Execute();
}

并这样称呼它:

return Execute<Test, RequestTest, ResponseTest>(request);

但我不想每次需要调用Execute方法时都必须指定所有三种类型。

我终于找到了解决问题的方法。我并没有真正意识到协方差概念,这帮助我实现了我想要的东西。 在我对原始问题中给出的样本所做的更改下方。

添加了协变泛型接口

public interface IWebMethodBase<out T1, out T2>
where T1 : Request
where T2 : Response
{
T2 Execute();
}

然后修改了WebMethodBase<>类以实现此接口

public abstract class WebMethodBase<TInput, TOutput> : Base, IWebMethodBase<TInput, TOutput>
where TInput : Request
where TOutput : Response
{
public abstract TOutput Execute();
protected TInput Input { get; set; }
public WebMethodBase(TInput input)
{
Input = input;
}
}

还更改了继承上述类以反映其更改的Test类,最后是Execute方法

public static Response Execute<T>(Request request)
{
ConstructorInfo constructor = typeof(T).GetConstructor(new Type[] { request.GetType() });
T instance = (T)constructor.Invoke(new Object[] { request });
return instance.Execute();
}

并称它为">

ResponseTest result = Execute<Test>(new RequestTest()) as ResponseTest;

使用此协变接口允许调用方使用继承或派生自应用约束的任何泛型类型,并使其按我想要的方式工作。

我唯一试图改进的是最终调用者所需的强制转换,但我没有找到任何方法来实现这一点,显然是编译器本身拒绝隐式转换返回值到其派生实现。我知道使用我不推荐的option strict offVB.Net是可能的,但仅此而已。

如果有人对我的解决方案或改进有更好的解决方案或改进,请随时编辑此答案。

最新更新