C#玩泛型、反射和类型推理
我正在做一些泛型类型的实验,我正在努力实现我想要的。事实上,我甚至不确定是否有可能做到这一点。以下是一个示例:C#玩泛型、反射和类型推理,c#,generics,reflection,C#,Generics,Reflection,我正在做一些泛型类型的实验,我正在努力实现我想要的。事实上,我甚至不确定是否有可能做到这一点。以下是一个示例: public class Request { } public class RequestTest : Request { } public class Response { } public class ResponseTest : Response { } public abstract class Base { // some stuff } public abst
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());
}
}
由于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();
}
私有静态TOutput执行(TInput输入)
其中TMethod:WebMethodBase
放置位置:请求
where TOutput:Response,new()
{
TOutput输出=新的TOutput();
var constructor=typeof(TMethod).GetConstructor(新类型[]{typeof(TInput),typeof(TOutput)});
TMethod实例=(TMethod)构造函数.Invoke(新对象[]{input,output});
返回instance.Execute();
}
这样说:
return Execute<Test, RequestTest, ResponseTest>(request);
返回执行(请求);
但我不希望每次需要调用
Execute
方法时都必须指定这三种类型。我终于找到了解决问题的方法。我并没有真正意识到这个概念,这帮助我实现了我想要的。
下面是我对原始问题中给出的样本所做的更改
添加了一个协变通用接口
public interface IWebMethodBase<out T1, out T2>
where T1 : Request
where T2 : Response
{
T2 Execute();
}
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;
}
}
那就叫它
ResponseTest result = Execute<Test>(new RequestTest()) as ResponseTest;
ResponseTest result=Execute(newrequesttest())作为ResponseTest;
使用此协变接口允许调用方使用继承或派生自应用的约束的任何泛型类型,并使其按我所希望的方式工作
我唯一试图改进的是最终调用方所需的强制转换,但我没有找到任何方法来实现这一点,显然是编译器本身拒绝隐式地将返回值强制转换为其派生实现。我知道在VB.Net
中可以使用选项strict off
,我不建议这样做,但仅此而已
如果有人对我的问题有更好的解决方案或改进,请随意编辑此答案。如果不清楚构造的是哪一个,您能否简单地向构造函数添加一个断点并查看?
request
在这一行中不存在return Execute(request,new ResponseTest())
,这里是不是指输入?@LasseV.Karlsen其他开发人员不清楚是否会查看调用代码。@PavelAnikhouski是的,我确实编辑了这个问题。我认为更糟糕的问题是,如果有多个类实现WebMethodBase
,其中一个是任意选择的,没有人知道这一点。我更喜欢单个
而不是第一个或默认
,尤其是因为下面的代码假设第一个
部分成功,并且无法处理默认
。
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;