返回抽象泛型的适当混凝土类型

时间:2011-04-19 19:29:18

标签: c# dependency-injection inversion-of-control ioc-container structuremap

我在使用StructureMap配置时遇到了困难。我有一个ValidationProvider接受一个Func作为其验证工厂。我需要使用结构映射来提供它,以便它知道它应该返回什么Validator(abstract)的实现。我猜你已经很困惑,所以这里有一些代码可以解决问题:

public class ValidationProvider : IValidationProvider
{
    private readonly Func<Type, IValidator> _validatorFactory;

    public ValidationProvider(Func<Type, IValidator> validatorFactory)
    {
        _validatorFactory = validatorFactory;
    }

如您所见,验证提供程序委派了确定validatorFactory所需的IValidator实现的功能。我也有Validator实现了IValidator。

public abstract class Validator<T> : IValidator
{
    IEnumerable<ValidationResult> IValidator.Validate(object entity)
    {
        if (entity == null) throw new ArgumentNullException("entity");

        return this.Validate((T)entity);
    }

    protected abstract IEnumerable<ValidationResult> Validate(T entity);
}

然后我为每个需要验证的实体都有一个Validator实例,例如:

public sealed class BidValidator : Validator<Bid>
{
    protected override IEnumerable<ValidationResult> Validate(Bid bid)
    {
        if (bid.User.HasEnoughCredits(bid.Item.Category.ListingPrice) == false)
            yield return new ValidationResult("InsufficientCredits", "Not enough credits.");
        if(bid.Item.IsValidBidAmount(bid.Amount) == false)
            yield return new ValidationResult("Amount", "Bid amount has to be higher than last posted bid.");
        if(bid.User.OwnsItem(bid.Item.Id))
            yield return new ValidationResult("InvalidBidder", "User cannot bid on his/her own items.");
    }
}

我有一个NullValidator,当没有抽象Validator的实现时,它应该是默认值

public sealed class NullValidator<T> : Validator<T>
{
    protected override IEnumerable<ValidationResult> Validate(T entity)
    {
        return Enumerable.Empty<ValidationResult>();  
    }
}

所以现在在StructureMap中我需要把事情联系在一起,但我无法让它发挥作用......这就是我得到的:

            x.For(typeof(Validator<>)).Use(typeof(NullValidator<>));
            x.For<Validator<Bid>>().Use<BidValidator>();
            x.For<Validator<Rating>>().Use<RatingValidator>();
            x.For<Validator<TopLevelCategory>>().Use<TopLevelCategoryValidator>();
        });

        Func<Type, IValidator> validatorFactory = type =>
        {
            var valType = typeof(Validator<>).MakeGenericType(type.GetType());
            return (IValidator) ObjectFactory.GetInstance(valType);
        };

        container.Configure(x => x.For<IValidationProvider>().Use(() => new ValidationProvider(validatorFactory)));

但是说return (IValidator) ObjectFactory.GetInstance(valType);的行不断抛出此异常:

  

StructureMap异常代码:202 No.   为。定义的默认实例   PluginFamily   Sharwe.Services.Validation.Validator`1 [System.RuntimeType,   mscorlib,版本= 4.0.0.0,   文化=中性,   公钥= b77a5c561934e089]]   Sharwe.Services,版本= 1.0.0.0,   Culture = neutral,PublicKeyToken = null

任何方式我都可以搞定这个?

P.S:如果有更简单的方法,我会很高兴知道这件事。这不是我实现的,我只是喜欢它,并且认为值得一试......

2 个答案:

答案 0 :(得分:2)

更改以下代码:

Func<Type, IValidator> validatorFactory = type =>
{
    var valType = typeof(Validator<>).MakeGenericType(type.GetType());
    return (IValidator) ObjectFactory.GetInstance(valType);
};

要:

Func<Type, IValidator> validatorFactory = type =>
{
    var valType = typeof(Validator<>).MakeGenericType(type);
    return (IValidator) ObjectFactory.GetInstance(valType);
};

您正在提供Type参数并致电type.GetType(),该Type会返回Type的{​​{1}}个实例...呃......还在跟着我吗?异常消息实际上说明了一切:

  

未定义默认实例   验证器; System.RuntimeType&GT;

答案 1 :(得分:1)

我认为问题是ObjectFactory和你创建的Container对象的混合使用......

ObjectFactory创建并管理容器实例,因此如果您创建另一个容器,它们将具有不同的配置。

如果只使用容器对象或仅使用ObjectFactory,它应该可以工作。