开发者

How can I inject a property only if the value is non-null at runtime using Unity?

开发者 https://www.devze.com 2023-01-10 17:39 出处:网络
I have an interface to resolve and one of the mapped object\'s dependencies has a property on it which I would like to set with a value that I only have available when I resolve the top level object.

I have an interface to resolve and one of the mapped object's dependencies has a property on it which I would like to set with a value that I only have available when I resolve the top level object.

There's no valid default value for the property. If its not set it should be null and it should only be set if the value that I have available at resolve time is not null.

Is this conditional property injection possible?

I tried this...

container.RegisterType<ProductInstanceValidatorBase, CartItemPurchaseTypeValidator>("CartItemPurchaseTypeValidator", new InjectionProperty("AccountEntity", null);

... but it said I couldn't use a null value!

I also tried this on the resolve...

container.Resolve<ProductInstanceValidatorBase>(new PropertyOverride("AccountEntity", value));

...but this throws an exception when the value is null. It says,

Parameter type inference does not work for null values. Indicate the parameter type explic开发者_JAVA技巧itly using a properly configured instance of the InjectionParameter or InjectionParameter classes. Parameter name: parameterValue

Basically I'm looking to register a property that is only set with an override and then only if the override value is non-null. Any ideas? Surely from a semantic point of view, property injection should be optional.

Cheers, Ian.


One potential fix to this problem is to implement a Null Object Pattern and pass Account.Empty when you haven't got a valid account. Here is what a class could look like:

public class Account {
   public static readonly Account Empty = new Account();
}

//at resolution time
Account account = null;
if (HasAccount) 
  account = GetAccount();
else 
  account = Account.Empty;

container.Resolve<ProductInstanceValidatorBase>(new PropertyOverride("AccountEntity", account));

This way the account is never null and Entity framework wouldn't complain.

However I sense that you might have a larger problem with the design of the system. IoC container allows a more loosely coupled system, where the wiring of the components is defined before the program is run, not while it's run. Judging by the name, AccountEnyity is an entity class, not a service class, and you normally do not register entities with the IoC container, only services.

In the light of the above I would suggest that AccountEntity shouldn't be an injectable property, but instead a normal property. You then externalize the ProductInstanceValidatorBase creation into a factory and let it take care of setting AccountEntity property

public interface IProductInstanceValidatorFactory{
  ProductInstanceValidatorBase Create(Account account);
}
public class ProductInstanceValidatorFactory : IProductInstanceValidatorFactory{
  public ProductInstanceValidatorBase Create(Account account){
     var validator = new ProductInstanceValidator();
     validator.AccountEnity = account;
     return validator;
  }
}

You don't even need to register ProductInstanceValidatorBase with Unity, but instead register the factory. This is how using the factory would look like:

Account account = null;
container.Resolve<IProductInstanceValidatorFactory>().Create(account);


You can use the InjectionParameter with null values, but you must specify the type. For your two scenarios I am assuming that your AccountEntity parameter is of type or derived from IAccount:

container.RegisterType<ProductInstanceValidatorBase, CartItemPurchaseTypeValidator>("CartItemPurchaseTypeValidator", new InjectionProperty<IAccount>(null);

Note that I have dropped the name as it is not specifically needed in the above scenario but it is needed for the scenario below.

container.Resolve<ProductInstanceValidatorBase>(new PropertyOverride("AccountEntity", new InjectionProperty<IAccount>(null)));


I would tend to agree with Igor. However, if you absolutely must resolve the Entity, why not just take your IoC container as a constructor dependency and then attempt to Resolve in the constructor?

0

精彩评论

暂无评论...
验证码 换一张
取 消