我為調度作業創建了以下抽象:
public abstract class BaseJob
{
public string? JobId { get; set; }
}
public interface IJobData
{ }
public interface IJob<in TJobData> where TJobData : IJobData
{
Task ExecuteAsync(TJobData jobData);
}
我使用工廠創造就業機會:
public class JobCreator<TJob, TJobData>
where TJob : IJob<TJobData>, new()
where TJobData : IJobData
{
public async Task ExecuteAsync(TJobData jobData)
{
var job = new TJob();
await job.ExecuteAsync(jobData);
}
}
作業是這樣安排的:
JobClient.Enqueue<JobCreator<ForgotPasswordJob, ForgotPasswordJobData>>(job => job.ExecuteAsync(jobData));
調度程式會將作業脫水到作業存盤,然后再將其脫水。我可以進入水化程序并列印型別:
Application.Common.Interfaces.JobCreator`2[Application.Jobs.ForgotPasswordJob,Application.Jobs.ForgotPasswordJobData]
在鉤子里面我可以接觸到水合作業
var job = schedulerHydrationMagic...
此時變數 job 是物件型別。是否可以投射它,以訪問 JobCreator 甚至更好的 ForgotPasswordJob?我想在 BaseJob 中設定 JobId。
我試過
var job = schedulerMagic as JobCreator<IJob<IJobData>, IJobData>
但是型別檢查抱怨 IJob 必須是非抽象型別。
uj5u.com熱心網友回復:
JobCreatornew()對泛型TJob引數有一個泛型約束:
public class JobCreator<TJob, TJobData>
where TJob : IJob<TJobData>, new() // <- here
where TJobData : IJobData
{
public async Task ExecuteAsync(TJobData jobData)
{
var job = new TJob();
await job.ExecuteAsync(jobData);
}
}
很明顯,您這樣做是為了可以呼叫new TJob().
但它解釋了為什么第一個泛型引數 - TJob- 必須始終是非抽象型別。
如果泛型型別的TJobData是IJob<IJobData>,那么在運行時的代碼行就等同于
var job = new IJob<IJobData>();
……沒有意義。你不能呼叫new介面(或抽象類)。這對我們來說很難發現,但對編譯器來說很容易。
強型別代碼的要點是編譯器在編譯應用程式時會檢測到這樣的事情。否則代碼看起來還不錯,你可以運行它,然后在運行時它發現它TJob沒有默認建構式。最好讓編譯器拒絕它并讓我們弄清楚它,而不是認為它沒問題然后得到一個更令人困惑的運行時錯誤。
對此沒有簡單的答案,因為問題就在設計的中間。這就是我所說的瘋狂兔子洞。這不是貶義 - 我自己做過。
我的第一個建議不是弄清楚如何使泛型起作用——而是停止嘗試做你正在做的事情。真的有很多可能的實作嗎?從代碼看來只有一個。因此,通過嘗試撰寫一個通用版本來處理未知的未來型別,您可能會嘗試解決您沒有的問題。在這種情況下,答案很簡單。不要試圖解決它。只需撰寫代碼來安排您需要安排的任何事情,而無需使用所有泛型。
如果你必須這樣做,那么你需要的是擺脫new()約束。這意味著您將無法呼叫new TJob(). 相反,您需要創建某種工廠介面,例如:
public interface IJobFactory
{
IJob<TJobData> Create<TJobData>() where TJobData : IJobData
}
然后你JobCreator看起來像這樣:
public class JobCreator<TJob, TJobData>
where TJob : IJob<TJobData>
where TJobData : IJobData
{
private readonly IJobFactory _jobFactory;
public JobCreator(IJobFactory jobFactory)
{
_jobFactory = jobFactory;
}
public async Task ExecuteAsync(TJobData jobData)
{
var job = _jobFactory.Create<TJobData>();
await job.ExecuteAsync(jobData);
}
}
但這并沒有解決問題。它只是移動了它。現在您必須弄清楚如何實作IJobFactory. (這已經令人困惑了,因為現在JobCreator并沒有真正創造作業——IJobFactory確實如此。)
這就是為什么我稱它為兔子洞的原因。它只是永遠持續下去。如果有任何方法可以修改代碼以擺脫問題而不是試圖解決它,那就更好了。
一旦你得到了你需要作業的代碼,而不會出現所有的混亂,那么解決更大問題的更好的解決方案很可能會成為焦點——如果有問題的話——就會成為焦點。
uj5u.com熱心網友回復:
我猜您需要一個進一步的介面來從調度程式中獲取作業。不能使用工廠介面,它有new約束。
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/376751.html
上一篇:如何使用System.Text.Json將json字串或流反序列化為Dictionary<string,string>
下一篇:發生錯誤1042:連接超時已過期
