SimpleIoC instance delete

Jan 5, 2014 at 6:45 PM
Edited Jan 5, 2014 at 6:47 PM
Hi

Simple question: it's possible to delete a single non-tokenized class instance without de-registering the interface from the SimpleIoC container?

The scenario is:
A window (based on a registered viewmodel) that makes a summary of the current loaded project file (injected with IoC). When I close and re-open another file the IoC keeps the old viewmodel instance without refreshing project data.

Now I have to do something like this to refresh dependencies:
SimpleIoC.Unregister<MyClass>(); // <- Istantiated
SimpleIoC.Register<MyClass>();

What about to add a de-instatiator method? (or a version of Unregister(bool deleteInstanceOnly))?

Thank you
Lorenzo
Jan 12, 2014 at 2:35 PM
Sorry for my first post.

I've found your second overload of Unregister<T>(instance) wich provides the functionality I was looking for.

Lorenzo
Jan 25, 2014 at 9:20 PM
Hi

after some tests I noticed that Unregister doesn't work properly.

If I do something like this:

// Creates a registration for my view model type resolving the class's dependencies
SimpleIoC.Default.Register<MyVMType>();

// Put the instance in a local variable
var myClassInstance = SimpleIoC.Default.GetInstance<MyVMType>();

// Unregister the instance. As the manual says: "this method only delete the previous created instance WITHOUT removing the registration."
SimpleIoC.Default.Unregister(myClassInstance);

// Try to get a new instance
SimpleIoC.GetInstance<MyVMType>(); // ERROR! Reports: "Type not found in cache without a key: MyVMType"

Am I doing something wrong?

Thank you!
Lorenzo
Jan 27, 2014 at 11:05 AM
Hmmm,

It does appear to work like that, Unity would just create a new class instance.
// Cleanup
((IDisposable)ServiceLocator.Current.GetInstance<ICustomerDataService>()).Dispose();
SimpleIoc.Default.Unregister<ICustomerDataService>();

//Fails
ICustomerDataService test = ServiceLocator.Current.GetInstance<ICustomerDataService>();

//Works
SimpleIoc.Default.Register<ICustomerDataService, CustomerDataService>();
ICustomerDataService test = ServiceLocator.Current.GetInstance<ICustomerDataService>();
I guess you can use a token if you want multiple instances but in my tests if you unregister a specific type you have to re-register before you can use it.

"Removes the given instance from the cache. The class itself remains registered and can be used to create other instances."

As you say, the documentation would lead you to believe you just have to call GetInstance.
May 8, 2014 at 11:45 AM
I've come across the same problem. I've looked into the SimpleIoc.cs file in the source and the problem appears to be that when removing the instance, the factories are also removed. This results in SimpleIoc not being able to instantiate a new instance.

Based on the method description, I'd say this is a bug, but can easily be fixed if you have the code. In the example, I've just commented out the 'if(_factories...' bit and it seems to be working now.
        public void Unregister<TClass>(TClass instance)
            where TClass : class
        {
            lock (_syncLock)
            {
                var classType = typeof(TClass);

                if (_instancesRegistry.ContainsKey(classType))
                {
                    var list = _instancesRegistry[classType];

                    var pairs = list.Where(pair => pair.Value == instance).ToList();
                    for (var index = 0; index < pairs.Count(); index++)
                    {
                        var key = pairs[index].Key;

                        list.Remove(key);

                        //if (_factories.ContainsKey(classType))
                        //{
                        //  if (_factories[classType].ContainsKey(key))
                        //  {
                        //      _factories[classType].Remove(key);
                        //  }
                        //}
                    }
                }
            }
        }
Coordinator
May 8, 2014 at 1:16 PM
Hi,

It sounds like a bug to me as well. I will think about it just to make sure that this is not breaking anything but I agree that the expected behavior should be to NOT remove the factory.

Let me check that out.

Thanks
Laurent
May 8, 2014 at 4:21 PM
Hi Laurent,

Just noticed that the same issue seems to appear in the "public void Unregister<TClass>(string key)" method as well.

( Been exploring the code a bit. Loving the toolkit though! :-) )

Regards,
Llewelyn
Jun 11, 2014 at 12:01 PM
Edited Jun 18, 2014 at 4:37 AM
Hi Laurent,

Run into the same issue recently. Tried it out, the fix from llewelynrex works. Is it possible to implement this fix to the next version?

Otherwise, I really like this toolkit though!

Regards
zuberbro
Jun 20, 2014 at 12:13 PM
I've created Issue 7636 for this problem, zuberbro. Could you cast your vote there? Might give this problem a higher priority if more people vote for it. At the moment, there are only 2 votes.

Kind Regards,
Llewelyn
Jun 20, 2014 at 12:57 PM
I have talked to Laurent last Monday. He will review this and most likely fix it in a next release. - I just give a vote, didn't see it.
Cheers
zuberbro
Jun 20, 2014 at 3:51 PM
Ah, brilliant! Looking forward to the new release. :)
Nov 18, 2014 at 6:27 AM
I think there has been a new release since the last post here, but it seems the bug is still there. Could you please fix the issue?
Coordinator
Nov 18, 2014 at 7:13 AM
Hi,

The V5 release was a big construction site where I finally took the Portable class library as the main branch. This simplifies the process for me and will allow me to release new versions faster. It might be a little frustrating for the users because I decided to release V5 before I was able to address all the bugs but the situation is much cleaner now and I will address this particular bug next.

Sorry for the delay and be assured that this is important to me.

Cheers
Laurent
Coordinator
Feb 5, 2015 at 3:35 PM
Hi,

Here is an update: I fixed the issue by changing slightly the way that Unregister(TService instance) works. Now you can do this:
            SimpleIoc.Default.Reset();
            SimpleIoc.Default.Register<TestClass1>();

            Assert.IsTrue(SimpleIoc.Default.IsRegistered<TestClass1>());
            Assert.IsFalse(SimpleIoc.Default.ContainsCreated<TestClass1>());

            const string key = "key1";
            var instance1 = SimpleIoc.Default.GetInstance<TestClass1>(key);

            Assert.IsTrue(SimpleIoc.Default.IsRegistered<TestClass1>());
            Assert.IsTrue(SimpleIoc.Default.ContainsCreated<TestClass1>());

            var instance2 = SimpleIoc.Default.GetInstance<TestClass1>(key);
            Assert.AreSame(instance1, instance2);

            SimpleIoc.Default.Unregister(instance1);

            Assert.IsTrue(SimpleIoc.Default.IsRegistered<TestClass1>());
            Assert.IsFalse(SimpleIoc.Default.ContainsCreated<TestClass1>());

            var instance3 = SimpleIoc.Default.GetInstance<TestClass1>(key);
            Assert.AreNotSame(instance1, instance3);
or (more to the point of this discussion), you can also do:
            SimpleIoc.Default.Reset();
            SimpleIoc.Default.Register<TestClass1>();

            Assert.IsTrue(SimpleIoc.Default.IsRegistered<TestClass1>());
            Assert.IsFalse(SimpleIoc.Default.ContainsCreated<TestClass1>());

            var instance1 = SimpleIoc.Default.GetInstance<TestClass1>();

            Assert.IsTrue(SimpleIoc.Default.IsRegistered<TestClass1>());
            Assert.IsTrue(SimpleIoc.Default.ContainsCreated<TestClass1>());

            var instance2 = SimpleIoc.Default.GetInstance<TestClass1>();
            Assert.AreSame(instance1, instance2);

            SimpleIoc.Default.Unregister(instance1);

            Assert.IsTrue(SimpleIoc.Default.IsRegistered<TestClass1>());
            Assert.IsFalse(SimpleIoc.Default.ContainsCreated<TestClass1>());

            var instance3 = SimpleIoc.Default.GetInstance<TestClass1>();
            Assert.AreNotSame(instance1, instance3);
Notice that this is a breaking change which I think makes sense, as this promotes a much better practice here. Before, if you were unregistering the only instance and then trying to reinstance, you would get an ActivationException. Now, this just works.

I hope that this is not going to break too much code but I don't think so. Relying on an exception being thrown is not a great practice ;) and it was rather weird having to "force unregister" before getting a new instance again.

This change is implemented now and will come in V5.1 coming up most probably this weekend (8 Feb 2015).

Thanks for the patience everyone.
Laurent
Coordinator
Feb 6, 2015 at 4:12 PM
DLLs are available here:
http://1drv.ms/1ylP1TS

Nuget will be updated ASAP.