简体   繁体   English

使处理程序通用

[英]Making Handlers Generic

So I'm writing a C# System.Commandline app, and I've noticed that my methods all follow a similar structure - each Handler class has a single public method, RunHandlerAndReturnExitCode, taking a different set of options which I've encapsulated into a class to be passed as the parameter.所以我正在编写一个 C# System.Commandline 应用程序,我注意到我的方法都遵循类似的结构 - 每个处理程序 class 都有一个公共方法 RunHandlerAndReturnExitCode,它采用一组不同的选项,我封装到一个class 作为参数传递。 Like below:如下所示:

public class FirstHandler
{
    public int RunHandlerAndReturnExitCode(FirstOptions options) { }
}

public class SecondHandler
{
    public int RunHandlerAndReturnExitCode(SecondOptions options) { }
}

And so on.等等。 I've tried making an OptionsBase abstract class, and having my other Options classes inherit from it, then created a handler interface like the below:我尝试制作一个 OptionsBase 抽象 class,并让我的其他 Options 类继承自它,然后创建一个如下所示的处理程序接口:

internal interface IHandler
    {
        int RunHandlerAndReturnExitCode<T>(T options) where T : OptionsBase;
    }

With the handlers looking like:处理程序看起来像:

public class FirstHandler : IHandler
{
    public int RunHandlerAndReturnExitCode<FirstOptions>(FirstOptions options) { }
}

Edit: I also have the Options classes inheriting from OptionsBase:编辑:我也有从 OptionsBase 继承的 Options 类:

public class FirstOptions : OptionsBase
{
    public string FirstProperty { get; set; }
}

And the OptionsBase class:和 OptionsBase class:

public abstract class OptionsBase { }

But this returns the error "The constraints for type parameter 'FirstOptions' must match the constraints for type parameter T. (Consider using an explicit interface implementation instead).但这会返回错误“类型参数 'FirstOptions' 的约束必须与类型参数 T 的约束匹配。(请考虑改用显式接口实现)。

Where am I going wrong?我哪里错了? Is this even the right approach?这甚至是正确的方法吗?

you are setting abstraction and constraints on function level, which means whichever class will implement that interface will implement an abstract method with its constraints.您正在 function 级别上设置抽象和约束,这意味着无论 class 将实现该接口,都将实现具有其约束的抽象方法。

public class Program
{
    public static void Main()
    {
        new GenericHandler<FirstOptions>().RunHandlerAndReturnExitCode(new FirstOptions
        {
            FirstProperty = "FirstOptionProp",
            SomeBaseOptionOne = 1,
            SomeBaseOptionTwo = 2,
        });
        new FirstHandler().RunHandlerAndReturnExitCode(new FirstOptions
        {
            FirstProperty = "FirstOptionProp",
            SomeBaseOptionOne = 1,
            SomeBaseOptionTwo = 2,
        }); ;
    }
}

public abstract class OptionsBase
{
    public int SomeBaseOptionOne { get; set; }
    public int SomeBaseOptionTwo { get; set; }
}

public class FirstOptions : OptionsBase
{
    public string FirstProperty { get; set; }
}

internal interface IHandler<T>
    where T : OptionsBase
{
    int RunHandlerAndReturnExitCode(T options);
}

public class FirstHandler : IHandler<FirstOptions>
{
    public int RunHandlerAndReturnExitCode(FirstOptions options)
    {
        return options.SomeBaseOptionTwo;
    }
}

public class GenericHandler<T> : IHandler<T>
{
    public int RunHandlerAndReturnExitCode(T options)
    {
        //TODO: do some generic imlementation

        return 0;
    }
}

you can register it in services as:您可以在服务中将其注册为:

services.AddScoped(typeof(IHandler<FirstOptions>), typeof(FirstHandler))
services.AddScoped(typeof(IHandler<>), typeof(GenericHandler<>))

Based on what you are trying to do, you can do it like the following.根据您要执行的操作,您可以执行以下操作。

The Interface should have the Generic Type set on it, ie.接口应该设置通用类型,即。 IHandler<T> where T: OptionsBase , Then have separate implementations of the FirstHandler and SecondHandler . IHandler<T> where T: OptionsBase ,然后分别实现FirstHandlerSecondHandler

public class OptionsBase
{

}

public class FirstOptions : OptionsBase
{

}

public class SecondOptions : OptionsBase
{

}

internal interface IHandler<T> where T : OptionsBase
{
    int RunHandlerAndReturnExitCode(T options);
}

public class FirstHandler : IHandler<FirstOptions>
{
    public int RunHandlerAndReturnExitCode(FirstOptions options)
    {
        throw new NotImplementedException();
    }
}    

public class SecondHandler : IHandler<SecondOptions>
{
    public int RunHandlerAndReturnExitCode(SecondOptions options)
    {
        throw new NotImplementedException();
    }
}

This gives you the ability to test each handler individually, introduce a base abstract class, and also use DependencyInjection for the options: Like the following example:这使您能够单独测试每个处理程序,引入基本抽象 class,并使用 DependencyInjection 作为选项:如以下示例:

public abstract class AbstracHandler<T> : IHandler<T> where T : OptionsBase
{
    protected readonly T _options;

    public AbstracHandler(T options)
    {
        _options = options;
    }
    public abstract int RunHandlerAndReturnExitCode(T options);
}

public class FirstHandler : AbstracHandler<FirstOptions>
{
    public FirstHandler(FirstOptions options) : base(options)
    {

    }

    public override int RunHandlerAndReturnExitCode(FirstOptions options)
    {
        throw new NotImplementedException();
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM