[英]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.