[英]C# Playing with generics, reflection and type inference
我正在用泛型类型做一些实验,我正在努力实现我正在寻找的东西。 我实际上不确定是否有可能做到这一点。 这是一个示例:
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;
使用这个协变接口允许调用者使用从应用约束继承或派生的任何泛型类型,并使其按我的意愿工作。
我试图改进的唯一一件事是最终调用者所需的转换,但我没有找到任何方法来实现这一点,显然是编译器本身拒绝将返回值隐式转换为其派生实现。 我知道在VB.Net
使用我不推荐的option strict off
,但仅此而已。
如果有人对我的解决方案有更好的解决方案或改进,请随时编辑此答案。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.