Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/337.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# 更改现有对象的依赖项_C#_Dependency Injection_Structuremap - Fatal编程技术网

C# 更改现有对象的依赖项

C# 更改现有对象的依赖项,c#,dependency-injection,structuremap,C#,Dependency Injection,Structuremap,我正在处理WPF应用程序。 我使用注入依赖项。 存在一些服务层类,它们从构造函数中提供参数。 我传递给构造函数的值将更改运行时。 表示层的类使用服务为用户表示数据。每当值发生变化时,我就用新值再次注入服务。但表示层的活动实例返回以前的值。 为了更好地理解,我准备了一个简单的例子 // static class that keeps some value public class ValueKeeper { public static string Value { get; set; }

我正在处理WPF应用程序。 我使用注入依赖项。 存在一些服务层类,它们从构造函数中提供参数。 我传递给构造函数的值将更改运行时。 表示层的类使用服务为用户表示数据。每当值发生变化时,我就用新值再次注入服务。但表示层的活动实例返回以前的值。 为了更好地理解,我准备了一个简单的例子

// static class that keeps some value
public class ValueKeeper

{
    public static string Value { get; set; }
}

public interface IService
{
    string Value { get; set; }
}
// Service layer class
public class Service : IService
{
    // default constructor
    public Service(string value)
    {
        Value = value;
    }

    #region IService Members

    public string Value { get; set; }

    #endregion
}


public class Program
{
    private readonly IService _service;
    //injecting service class
    public Program(IService service)
    {
        _service = service;
    }
    // structuremap configuration
    private static void Config()
    {
        ObjectFactory.Initialize(x => x.Scan(scanner =>
                                                 {
                                                     scanner.TheCallingAssembly();

                                                     scanner.WithDefaultConventions();
                                                     x.For<IService>().CacheBy(InstanceScope.Hybrid).Use(() =>
                                                                                                             {
                                                                                                                 var service = new Service("value1");
                                                                                                                 return service;
                                                                                                             });
                                                 }));
    }
    // structuremap configuration after value changed.
    private static void ReConfig()
    {
        ObjectFactory.Configure(x => x.Scan(scanner =>
                                                 {
                                                     x.For<IService>().CacheBy(InstanceScope.Hybrid).Use(() =>
                                                                                                             {
                                                                                                                 var service =new Service(ValueKeeper.Value);
                                                                                                                 return service;
                                                                                                             });
                                                 }));
    }


    private string PresentationMethod()
    {
        return _service.Value;
    }

    private static void Main(string[] args)
    {
        Config();  // Firtst time injecting dependencies
        var prog = ObjectFactory.GetInstance<Program>(); 
        Console.WriteLine(prog.PresentationMethod()); // returns "value1"
        ValueKeeper.Value = "value 2"; //changing static property
        ReConfig(); // reconfig  service class with new property
         Console.WriteLine(prog.PresentationMethod()); // it returns value1 but I expect value2 .
        Console.ReadKey();
    }
}
真正的应用程序包含许多表示类和服务类。 如何使用新对象和值更改实时服务实例

更新: 我看到了林克。通过使用Setter注入,似乎可以更改现有对象。 塞特注射是我的解决方案吗

您可以使用在运行时轻松跟踪并在同一接口的实例之间切换。下面是一个简单的例子:

var container = new Container(x => x.Scan(scan =>
{
    scan.TheCallingAssembly();
    scan.WithDefaultConventions();
    scan.AddAllTypesOf<IDiscountCalculator>();
}));
var strategy = container.GetInstance<IDiscountStrategy>();
Console.WriteLine(strategy.GetDiscount("Regular", 10)); // 0
Console.WriteLine(strategy.GetDiscount("Normal", 10)); // 1
Console.WriteLine(strategy.GetDiscount("Special", 10)); // 5
或者,如果您有希望立即处理的短期依赖项,则应该注入一个,以便按需创建它们

public ISomeObjectFactory
{
    ISomeObject Create();
    void Release(ISomeObject someObject);
}

public class SomeObjectFactory
    : ISomeObjectFactory
{
    //private readonly IAclModule aclModule;

    // Inject dependencies at application startup here
    //public SiteMapPluginProviderFactory(
    //    IAclModule aclModule
    //    )
    //{
    //    if (aclModule == null)
    //        throw new ArgumentNullException("aclModule");
    //
    //    this.aclModule = aclModule;
    //}

    public ISomeObject Create(IState state)
    {
        return new SomeObject(state);
        // return new SomeObject(state, this.aclModule);
    }

    pubic void Release(ISomeObject someObject)
    {
        var disposable = someObject as IDisposable;
        if (disposable != null)
        {
            disposable.Dispose();
        }
    }
}
然后使用类似于:

public class Consumer : IConsumer
{
    private readonly ISomeObjectFactory someObjectFactory;

    public Consumer(ISomeObjectFactory someObjectFactory)
    {
        if (someObjectFactory == null)
            throw new ArgumentNullException("someObjectFactory");
        this.someObjectFactory = someObjectFactory; 
    }

    public void DoSomething(IState state)
    {
        var instance = this.someObjectFactory.Create(state);
        try
        {
            // Use the instance here.
        }
        finally
        {
            this.someObjectFactory.Release(instance);
        }
    }
}
虽然这里没有显示,但是如果需要,工厂可以在不同的类之间切换,或者您也可以在创建同一类型的类时将不同的依赖项传递给本例中的IState


除了最罕见的情况外,在所有情况下都应该避免使用它。

您不能将这个注入值也作为接口的属性,这样您就不必每次都注入类的新实例了吗?如果每次只更改构造函数参数,那么重新注入依赖项似乎是一种可怕的做法。@SimonWhitehead我不能。因为我举例的服务类实际上是.NET库中的一个类。DbContext。我必须将连接字符串传递给它的构造函数。@shaahin没有IoC跟踪它创建的实例,除非它的单例AFAIK。所以,简单的回答是,没有办法对容器执行此操作。您可以做的是将GetInstance方法包装到您控制的方法中,并跟踪您自己创建的实例,以便随时更改它们的依赖关系。但是,我建议您不要这样做,因为在整个应用程序中跟踪实例绝非易事。你应该重新考虑你的理由,重新考虑解决办法。@tucaz谢谢。使用“Setter注入”怎么样?似乎我需要一个解决方案来改变初始化对象的依赖关系。Setter注入只是将依赖关系传递给对象的另一种方式。您正在使用构造函数注入,其中依赖项通过构造函数传递。在Setter注入中,通过在属性中调用set方法来注入它们。那不是你需要的。无论注入方法是什么,IoC容器都不会为您跟踪和更改现有实例。
public class Consumer : IConsumer
{
    private readonly ISomeObjectFactory someObjectFactory;

    public Consumer(ISomeObjectFactory someObjectFactory)
    {
        if (someObjectFactory == null)
            throw new ArgumentNullException("someObjectFactory");
        this.someObjectFactory = someObjectFactory; 
    }

    public void DoSomething(IState state)
    {
        var instance = this.someObjectFactory.Create(state);
        try
        {
            // Use the instance here.
        }
        finally
        {
            this.someObjectFactory.Release(instance);
        }
    }
}