如何在C#中存储和使用接口实现列表?

问题描述 投票:0回答:1

我想提供一种快速注册 HangFire 工作的方法。它们都实现了 IJob 接口(其中包含 Task Run())。问题是我无法获得接受以这种方式创建的模型的列表。示例:

工作示例:

public class CheckFilesJob() : IJob
{
    async Task Run()
    {
        // do something here
    }

我想在注册时使用的型号:

public class JobConfiguration<T>
    where T : IJob
{
    public JobConfiguration(string key, string queueName, Expression<Func<T, Task>> jobExpression, string cronExpression)
    {
        Key = key;
        QueueName = queueName;
        JobExpression = jobExpression;
        CronExpression = cronExpression;
    }

    public string Key { get; set; }

    public string QueueName { get; set; }

    public Expression<Func<T, Task>> JobExpression { get; set; }

    public string CronExpression { get; set; }
}

我想如何实例化列表:

new List<JobConfiguration<IJob>>
        {
            new RecurringJobConfiguration<CheckFilesJob>("Check Files",
                jobsConfiguration.Value.QueueName,
                x => x.Run(),
                jobsConfiguration.Value.CheckFilesSchedule),
            new RecurringJobConfiguration<AnotherJob>("Another Job", jobsConfiguration.Value.QueueName, x => x.Run(), jobsConfiguration.Value.AnotherJobSchedule)
        };

以及我想如何使用它:

    public static void HandleJobRegistration(
        this IServiceProvider serviceProvider,
        IEnumerable<JobConfiguration<IJob>> configurations)
    {
        // register each job here
    }

问题:

  1. 我无法创建 IJob 列表,因为实现无法转换为接口(CS1503)。
  2. 我似乎无法跳过将 IJobConfiguration 设置为通用,否则传递给模型的 jobExpression 属于接口(而不是实现)。
  3. 我不能使用 () => new CheckFilesJob().Run(),因为它看起来很丑陋,需要为作业提供多少服务。

尝试使用泛型和非泛型类,期望能够以某种方式提供正确的表达。尝试了不同的方法将列表作为函数的参数提供,但无济于事。

c# list generics implementation hangfire
1个回答
0
投票

要创建一种快速注册全部实现

IJob
接口的 HangFire 作业的方法并克服您所描述的问题,您需要解决特定作业实现和通用接口
IJob
之间的类型兼容性问题。以下是实现这一目标的分步方法:

  1. 定义接口和实现:确保正确定义您的
    IJob
    接口和作业实现。
public interface IJob
{
    Task Run();
}

public class CheckFilesJob : IJob
{
    public async Task Run()
    {
        // do something here
    }
}

public class AnotherJob : IJob
{
    public async Task Run()
    {
        // do something here
    }
}
  1. 定义作业配置类:创建一个通用的
    JobConfiguration
    类来保存每个作业的配置。
public class JobConfiguration<T>
    where T : IJob
{
    public JobConfiguration(string key, string queueName, Expression<Func<T, Task>> jobExpression, string cronExpression)
    {
        Key = key;
        QueueName = queueName;
        JobExpression = jobExpression;
        CronExpression = cronExpression;
    }

    public string Key { get; set; }
    public string QueueName { get; set; }
    public Expression<Func<T, Task>> JobExpression { get; set; }
    public string CronExpression { get; set; }
}
  1. 创建用于处理配置的非通用基类:为了方便注册过程,请创建一个非通用基类。
public abstract class JobConfigurationBase
{
    public string Key { get; set; }
    public string QueueName { get; set; }
    public string CronExpression { get; set; }
    public abstract LambdaExpression JobExpression { get; }
}

public class JobConfiguration<T> : JobConfigurationBase
    where T : IJob
{
    public JobConfiguration(string key, string queueName, Expression<Func<T, Task>> jobExpression, string cronExpression)
    {
        Key = key;
        QueueName = queueName;
        JobExpression = jobExpression;
        CronExpression = cronExpression;
    }

    public override LambdaExpression JobExpression { get; }
}
  1. 使用特定作业配置实例化列表:使用列表的非通用基类,然后实例化特定作业配置。
var jobConfigurations = new List<JobConfigurationBase>
{
    new JobConfiguration<CheckFilesJob>("Check Files",
        jobsConfiguration.Value.QueueName,
        x => x.Run(),
        jobsConfiguration.Value.CheckFilesSchedule),
    new JobConfiguration<AnotherJob>("Another Job",
        jobsConfiguration.Value.QueueName,
        x => x.Run(),
        jobsConfiguration.Value.AnotherJobSchedule)
};
  1. 注册作业:实现作业注册方法来处理每个作业配置的注册。
public static void HandleJobRegistration(
    this IServiceProvider serviceProvider,
    IEnumerable<JobConfigurationBase> configurations)
{
    foreach (var config in configurations)
    {
        var jobType = config.GetType().GetGenericArguments()[0];
        var jobInstance = serviceProvider.GetService(jobType);
        var jobExpression = config.JobExpression;

        RecurringJob.AddOrUpdate(
            config.Key,
            () => ((IJob)jobInstance).Run(),
            config.CronExpression,
            TimeZoneInfo.Local,
            config.QueueName);
    }
}

简单解释

  • 接口和实现:您有一个简单的接口
    IJob
    Run
    方法。每个作业(例如
    CheckFilesJob
    AnotherJob
    )都实现此接口。
  • 配置类:您创建一个通用的
    JobConfiguration<T>
    类来存储每个作业的设置,包括键、队列名称、作业表达式(如何运行作业)和 cron 表达式(何时运行作业)。
  • 非通用基类:非通用基类
    JobConfigurationBase
    有助于创建作业配置列表,而无需担心特定类型。
  • 实例化配置:您创建一个
    JobConfigurationBase
    列表并使用特定的作业配置填充它。
  • 作业注册:注册方法使用服务提供者获取作业实例并将其注册到HangFire。

这种方法解决了与类型兼容性相关的问题,并提供了一种注册多个作业的干净方法。

最新问题
© www.soinside.com 2019 - 2024. All rights reserved.