Dependency Injection and ValueTypes Problem

Topics: CAB & Smart Client Software Factory
Feb 24, 2006 at 2:45 AM
originally posted by: mamu300B

Hi all,

i found out that when you add a ValueType (enum, int etc.) to a locator and depend on the item in that locator, like you do when you use the DependencyAttribute, it happens that your ValueType is frequently lost.

The reason for this is that ValueTypes get boxed before added to the locator. And the locator stores the boxed object in its WeakRefDictionary. But when GarbageCollection starts, all boxed object references get destroyed. To see this happen, simply add a GC.Collect() call after adding your ValueType to the locator.

My solution will be to change the WeakRefDictionary so that it can handle and store ValueTypes as well.

Need code?
Kind regards
-Matthias
Feb 24, 2006 at 7:32 AM
originally posted by: BradWilsonMSFT

The best way to describe the problem, in my opinion, would be to provide us with unit tests which show the problem.

Thanks!
Feb 25, 2006 at 4:37 AM
originally posted by: mamu300B

Hi, sorry no unit test, but a complet sample:

using System;
using System.Collections.Generic;
using System.Text;

using Microsoft.Practices.CompositeUI;
using Microsoft.Practices.ObjectBuilder;

namespace ConsoleApplication1
{
public class MyManager
{
private int aValueTypeValue;

public int AValueTypeValue
{
get { return aValueTypeValue; }
set { aValueTypeValue = value; }
}

InjectionConstructor
public MyManager(Dependency(Name = "Test.ValueType")int aValueTypeValue)
{
this.aValueTypeValue = aValueTypeValue;
Console.WriteLine(this.aValueTypeValue);
}
}

public class MyWorkItem : WorkItem
{
protected override void OnRunStarted()
{
base.OnRunStarted();

DependencyResolutionLocatorKey locatorKey = new DependencyResolutionLocatorKey(typeof(int), "Test.ValueType");
this.InnerLocator.Add(locatorKey, 5);

Console.WriteLine(this.InnerLocator.Get<int>(locatorKey));

GC.Collect();

MyManager myManager = this.Items.AddNew<MyManager>();

Console.WriteLine(myManager.AValueTypeValue);
}
}


public class DemoApplication : CabApplication<MyWorkItem>
{
STAThread
public static void Main()
{
new DemoApplication().Run();
}

protected override void Start()
{
}
}
}
Feb 25, 2006 at 8:59 AM
originally posted by: BradWilsonMSFT

Your code illustrates the dichotomy in .NET between reference types and value types, rather than something specific about the locator.

The locator only holds weak references to things. When you pass a value type to something that takes an object, the value is boxed, so the thing you're putting into the locator is not a value type, but a boxed value type.

That boxed value type has no strong references to it. When you call GC.Collect(), the system believes that boxed value type is eligible for collection, and collects it.
Feb 25, 2006 at 10:52 AM
originally posted by: mamu300B

Brad,

thanks.
I know why those things happen.

But wouldn't it be handy when e.g. the WeakRefDirectory class threw an exception when someone tries to add a value type?
I'm not shure if all users here know that you are not allowed to use the DependencyAttribute on value types, like enums are. And it is no where noted that one can not do this with the Locator.

-Matthias
Feb 25, 2006 at 12:32 PM
originally posted by: BradWilsonMSFT

Let's separate ObjectBuilder from CAB, since this is a discussion board about CAB. CAB's use of the ObjectBuilder container always uses both the locator and lifetime container in concert with each other, which was the intended usage. People can add value types to the containers (WorkItems) in CAB, and they will stay, because the boxed reference has a strong reference in the lifetime container.

The code you provided is actually buggy for reference types, too, but in debug builds you won't see it because there would probably still be a local variable holding a reference to the object. In release builds, however, the GC is much more aggressive during collection.
Feb 25, 2006 at 10:18 PM
originally posted by: mamu300B

ok, i understand.

>>The code you provided is actually buggy for reference types, too.

and what will be the right way to add my own items to get found with the DependencyAttribute?

Thanks in advance
-Matthias
Feb 28, 2006 at 6:47 AM
originally posted by: BradWilsonMSFT

The right way would be something like this:

DependencyResolutionLocatorKey locatorKey = new DependencyResolutionLocatorKey(typeof(int), "Test.ValueType");
object o = 5;
this.InnerLocator.Add(locatorKey, o);
this.InnerLifetime.Add(o);
Feb 28, 2006 at 11:26 AM
originally posted by: mamu300B

ok, that makes sense ;-)

And should one use

this.InnerLifetime.Add(o);

for reference types that are not included in an Items collection too?

-Matthias
Feb 28, 2006 at 11:32 AM
originally posted by: BradWilsonMSFT

Yes.