Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/310.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
将具体类注入泛型c#.net核心_C#_Generics_Dependency Injection - Fatal编程技术网

将具体类注入泛型c#.net核心

将具体类注入泛型c#.net核心,c#,generics,dependency-injection,C#,Generics,Dependency Injection,我创建了一个泛型类: public class GenericCreate<T> : IRequest<Attempt<T>> where T: class { public T Model { get; } public GenericCreate(T model) => Model = model; } public class GenericCreateHandler<T> : IRequestHandler<G

我创建了一个泛型类:

public class GenericCreate<T> : IRequest<Attempt<T>> where T: class
{
    public T Model { get; }
    public GenericCreate(T model) => Model = model;
}

public class GenericCreateHandler<T> : IRequestHandler<GenericCreate<T>, Attempt<T>> where T : class
{
    private readonly NotNullValidator<T> _validator;
    private readonly DatabaseContext _databaseContext;

    public GenericCreateHandler(NotNullValidator<T> validator, DatabaseContext databaseContext)
    {
        _validator = validator;
        _databaseContext = databaseContext;
    }

    public async Task<Attempt<T>> Handle(GenericCreate<T> request, CancellationToken cancellationToken)
    {
        var generic = request.Model;
        var validationAttempt = _validator.Validate(generic).ToAttempt();
        if (validationAttempt.Failure) return validationAttempt.Error;
        
        _databaseContext.Add(generic);
        await _databaseContext.SaveChangesAsync(cancellationToken);

        return generic;
    }
}
但我想说的是:

public class CategoryValidator: NotNullValidator<Category>
{
    public CategoryValidator()
    {
        RuleFor(m => m.Id).NotEmpty();
        RuleFor(m => m.Name).NotEmpty();
    }
}
公共类CategoryValidator:NotNullValidator
{
公共类别验证器()
{
RuleFor(m=>m.Id).NotEmpty();
RuleFor(m=>m.Name).NotEmpty();
}
}
可以想象,我为项目中的每个实体都有一个验证器类,因此能够获得正确的验证器非常重要。
有人知道我如何使用.net core做到这一点吗?

正如第一个基于约定的示例所承诺的:

//列出名称中包含验证器的所有类,您可能希望在启动时这样做,以避免每次需要创建类时的开销
//您可能还想更改正在搜索的程序集。
var validators=Assembly.getExecutionGassembly().DefinedTypes.Where(t=>t.Name.Contains(“Validator”).ToList();
//您将能够从类型参数T(即typeof(T))中获得它
变量类型=类型(MyClass);
//这是您的约定=>验证程序
var validatorouse=validators.Single(v=>v.Name==$“{type.Name}Validator”);
//实例化验证器(您应该转换为抽象类型以更容易地使用它)
var obj=Activator.CreateInstance(ValidatorUse);

如果需要,可以使用其他方法实例化验证器:

只是为了澄清一下,以防其他人有此问题。 我使用响尾蛇回答并创建此扩展方法:

public static class ValidatorExtensions
{
    public static NotNullValidator<T> GetValidator<T>()
    {
        // List all classes containing validators in their name, you might want to do this at startup to avoid the overhead each time you need to create a class
        // You might also want to change which assembly you are searching in.
        var validators = Assembly.GetExecutingAssembly().DefinedTypes.Where(t => t.Name.Contains("Validator")).ToList();

        // You'll be able to get that from your type parameter T (i.e typeof(T))
        var type = typeof(T);

        //This is your convention => <ClassName>Validator   
        var validatorToUse = validators.Single(v => v.Name == $"{type.Name}Validator");

        //Instantiate your validator (you should cast to your abstract type to use it more easily)
        return (NotNullValidator<T>) Activator.CreateInstance(validatorToUse);
    }
}
公共静态类验证扩展
{
公共静态NotNullValidator GetValidator()
{
//列出所有名称中包含验证器的类,您可能希望在启动时这样做,以避免每次需要创建类时的开销
//您可能还想更改正在搜索的程序集。
var validators=Assembly.getExecutionGassembly().DefinedTypes.Where(t=>t.Name.Contains(“Validator”).ToList();
//您将能够从类型参数T(即typeof(T))中获得它
var类型=类型(T);
//这是您的约定=>验证程序
var validatorouse=validators.Single(v=>v.Name==$“{type.Name}Validator”);
//实例化验证器(您应该转换为抽象类型以更容易地使用它)
return(NotNullValidator)Activator.CreateInstance(validatorUse);
}
}
然后我可以像这样更新我的泛型类:

public class GenericCreate<T> : IRequest<Attempt<T>> where T: class
{
    public T Model { get; }
    public GenericCreate(T model) => Model = model;
}

public class GenericCreateHandler<T> : IRequestHandler<GenericCreate<T>, Attempt<T>> where T : class
{
    private readonly NotNullValidator<T> _validator;
    private readonly DatabaseContext _databaseContext;

    public GenericCreateHandler(DatabaseContext databaseContext)
    {
        _validator = ValidatorExtensions.GetValidator<T>();
        _databaseContext = databaseContext;
    }

    public async Task<Attempt<T>> Handle(GenericCreate<T> request, CancellationToken cancellationToken)
    {
        var generic = request.Model;
        var validationAttempt = _validator.Validate(generic).ToAttempt();
        if (validationAttempt.Failure) return validationAttempt.Error;
        
        _databaseContext.Add(generic);
        await _databaseContext.SaveChangesAsync(cancellationToken);

        return generic;
    }
}
公共类GenericCreate:IRequest其中T:class
{
公共T模型{get;}
公共通用创建(T模型)=>model=model;
}
公共类GenericCreateHandler:IRequestHandler其中T:class
{
私有只读NotNullValidator\u validator;
专用只读DatabaseContextu DatabaseContext;
公共GenericCreateHandler(DatabaseContext DatabaseContext)
{
_validator=ValidatorExtensions.GetValidator();
_databaseContext=databaseContext;
}
公共异步任务句柄(GenericCreate请求、CancellationToken CancellationToken)
{
var generic=request.Model;
var validationAttempt=_validator.Validate(通用).ToAttempt();
if(validationAttempt.Failure)返回validationAttempt.Error;
_databaseContext.Add(通用);
wait_databaseContext.saveChangesSync(cancellationToken);
返回泛型;
}
}
注意构造器:

_validator = ValidatorExtensions.GetValidator<T>();
\u validator=ValidatorExtensions.GetValidator();
这让我的测试顺利通过:

[TestFixture]
public class GenericCreateShould
{
    [Test]
    public async Task ThrowValidationErrorWhenGenericIsInvalid()
    {
        // Assemble
        var services = GenericCreateContext<Venue>.GivenServices();
        var handler = services.WhenCreateHandler();

        // Act
        var response = await handler.Handle(new GenericCreate<Venue>(new Venue()), CancellationToken.None);

        // Assert
        response.Success.Should().BeFalse();
        response.Result.Should().BeNull();
        response.Error.Should().BeOfType<ValidationError>();
        response.Error.Message.Should().Be("'Name' must not be empty.");
    }

    [Test]
    public async Task ReturnGeneric()
    {
        // Assemble
        var services = GenericCreateContext<Venue>.GivenServices();
        var handler = services.WhenCreateHandler();
        var model = new GenericCreate<Venue>(new Venue
        {
            Name = "Main branch"
        });

        // Act
        var response = await handler.Handle(model, CancellationToken.None);

        // Assert
        response.Success.Should().BeTrue();
        response.Error.Should().BeNull();
        response.Result.Should().BeOfType<Venue>();
    }
}

public class GenericCreateContext<T, TKey> : DatabaseContextContext where T: TClass<TKey>
{
    public static GenericCreateContext<T, TKey> GivenServices() => new GenericCreateContext<T, TKey>();

    public GenericCreateHandler<T> WhenCreateHandler() => new GenericCreateHandler<T>(DatabaseContext);
}

public class GenericCreateContext<T> : GenericCreateContext<T, int> where T: TClass<int>
{
}
[TestFixture]
公共类GenericCreateShould
{
[测试]
公共异步任务ThrowValidationErrorHengenerisInvalid()
{
//集合
var services=GenericCreateContext.GivenServices();
var handler=services.WhenCreateHandler();
//表演
var response=await handler.Handle(new GenericCreate(new Venue()),CancellationToken.None);
//断言
response.Success.Should().BeFalse();
response.Result.Should().BeNull();
response.Error.Should().BeOfType();
response.Error.Message.Should().Be(“'Name'不能为空”);
}
[测试]
公共异步任务ReturnGeneric()
{
//集合
var services=GenericCreateContext.GivenServices();
var handler=services.WhenCreateHandler();
var模型=新的通用创建(新场地)
{
Name=“主要分支机构”
});
//表演
var response=await handler.Handle(model,CancellationToken.None);
//断言
response.Success.Should().BeTrue();
response.Error.Should().BeNull();
response.Result.Should().BeOfType();
}
}
公共类GenericCreateContext:DatabaseContextContext,其中T:TClass
{
公共静态GenericCreateContext GivenServices()=>new GenericCreateContext();
public GenericCreateHandler WhenCreateHandler()=>新建GenericCreateHandler(DatabaseContext);
}
公共类GenericCreateContext:GenericCreateContext,其中T:TClass
{
}

第一个测试通过了,这就是问题所在,因为
NotNullValidator
不包含名称等规则,但是
VenueValidator
包含这些规则;这意味着扩展方法正在工作。

我看到了三种方法:属性、配置或约定。对于第一个,定义一个attibute,您将在描述需要注入的验证器的类上声明它。对于第二种情况,您可以有一个配置类,该类将每个类映射到它的验证器(可能变得非常冗长)。或者第三,您需要建立一个约定,例如基于类的名称,并使用反射来查找相应的验证器。我不知道如何执行您提到的任何选项,但是对于第三个,除了第二个选项之外,我所有的验证器都被命名为像
validator
,第一个和第三个是基于反射的。今天晚些时候,我会尝试在回答中写下一些例子。我也许会开始
[TestFixture]
public class GenericCreateShould
{
    [Test]
    public async Task ThrowValidationErrorWhenGenericIsInvalid()
    {
        // Assemble
        var services = GenericCreateContext<Venue>.GivenServices();
        var handler = services.WhenCreateHandler();

        // Act
        var response = await handler.Handle(new GenericCreate<Venue>(new Venue()), CancellationToken.None);

        // Assert
        response.Success.Should().BeFalse();
        response.Result.Should().BeNull();
        response.Error.Should().BeOfType<ValidationError>();
        response.Error.Message.Should().Be("'Name' must not be empty.");
    }

    [Test]
    public async Task ReturnGeneric()
    {
        // Assemble
        var services = GenericCreateContext<Venue>.GivenServices();
        var handler = services.WhenCreateHandler();
        var model = new GenericCreate<Venue>(new Venue
        {
            Name = "Main branch"
        });

        // Act
        var response = await handler.Handle(model, CancellationToken.None);

        // Assert
        response.Success.Should().BeTrue();
        response.Error.Should().BeNull();
        response.Result.Should().BeOfType<Venue>();
    }
}

public class GenericCreateContext<T, TKey> : DatabaseContextContext where T: TClass<TKey>
{
    public static GenericCreateContext<T, TKey> GivenServices() => new GenericCreateContext<T, TKey>();

    public GenericCreateHandler<T> WhenCreateHandler() => new GenericCreateHandler<T>(DatabaseContext);
}

public class GenericCreateContext<T> : GenericCreateContext<T, int> where T: TClass<int>
{
}