Skip to content

Commit

Permalink
Added WeakConstructorArgument and WeakPropertyValue that keep a weak …
Browse files Browse the repository at this point in the history
…reference to the value only so that Ninject has no reference on them when caching the created instance.

Closes #74
  • Loading branch information
remogloor committed Aug 8, 2013
1 parent f9ebe17 commit 88fcb06
Show file tree
Hide file tree
Showing 25 changed files with 3,719 additions and 27 deletions.
1 change: 1 addition & 0 deletions ReleaseNotes.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
Version 3.0.2
- Add: ToConstructor() can now accept results from methods as argument e.g. ToConstructor(_ => new Foo(this.GetBar())
- Add: WhenNoAncestorMatches, WhenAnyAncestorMatches and WhenNoAncestorNamed When overloads
- Add: WeakConstructorArgument and WeakPropertyValue that keep a weak reference to the value only so that Ninject has no reference on them when caching the created instance.
- Change: Added WhenAnyAncestorNamed and marked mispelled WhenAnyAnchestorNamed as obsolete
- Change: Release method was moved from IKernel to the IResolutionRoot interface
- Bugfix: Private properties of base class were not checked for existence of setter and Inject attribute
Expand Down
1 change: 1 addition & 0 deletions packages/repositories.config
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
<repositories>
<repository path="..\src\CommonServiceLocator.NinjectAdapter.Tests\packages.config" />
<repository path="..\src\CommonServiceLocator.NinjectAdapter\packages.config" />
<repository path="..\src\Ninject.Test\packages.config" />
</repositories>
Binary file added packages/xunit.1.9.1/lib/net20/xunit.dll
Binary file not shown.
5 changes: 5 additions & 0 deletions packages/xunit.1.9.1/lib/net20/xunit.dll.tdnet
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<TestRunner>
<FriendlyName>xUnit.net {0}.{1}.{2} build {3}</FriendlyName>
<AssemblyPath>xunit.runner.tdnet.dll</AssemblyPath>
<TypeName>Xunit.Runner.TdNet.TdNetRunner</TypeName>
</TestRunner>
Binary file not shown.
Binary file not shown.
Binary file not shown.
2,611 changes: 2,611 additions & 0 deletions packages/xunit.1.9.1/lib/net20/xunit.xml

Large diffs are not rendered by default.

Binary file added packages/xunit.1.9.1/xunit.1.9.1.nupkg
Binary file not shown.
21 changes: 21 additions & 0 deletions packages/xunit.1.9.1/xunit.1.9.1.nuspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>xunit</id>
<version>1.9.1</version>
<title>xUnit.net</title>
<authors>James Newkirk, Brad Wilson</authors>
<owners>James Newkirk, Brad Wilson</owners>
<licenseUrl>http://xunit.codeplex.com/license</licenseUrl>
<projectUrl>http://xunit.codeplex.com/</projectUrl>
<iconUrl>http://download.codeplex.com/Download?ProjectName=xunit&amp;DownloadId=365445</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>xUnit.net is a developer testing framework, built to support Test Driven Development, with a design goal of extreme simplicity and alignment with framework features.</description>
<releaseNotes />
<copyright />
<language />
<references>
<reference file="xunit.dll" />
</references>
</metadata>
</package>
Binary file not shown.
811 changes: 811 additions & 0 deletions packages/xunit.extensions.1.9.1/lib/net20/xunit.extensions.xml

Large diffs are not rendered by default.

Binary file not shown.
21 changes: 21 additions & 0 deletions packages/xunit.extensions.1.9.1/xunit.extensions.1.9.1.nuspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>xunit.extensions</id>
<version>1.9.1</version>
<title>xUnit.net: Extensions</title>
<authors>James Newkirk, Brad Wilson</authors>
<owners>James Newkirk, Brad Wilson</owners>
<licenseUrl>http://xunit.codeplex.com/license</licenseUrl>
<projectUrl>http://xunit.codeplex.com/</projectUrl>
<iconUrl>http://download.codeplex.com/Download?ProjectName=xunit&amp;DownloadId=365445</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Extensions for the xUnit.net framework, including data theories (data-driven tests) and several extension attributes.</description>
<releaseNotes />
<copyright />
<language />
<dependencies>
<dependency id="xunit" version="[1.9.1]" />
</dependencies>
</metadata>
</package>
30 changes: 30 additions & 0 deletions src/Ninject.Test/Integration/ConstructorArgumentTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,5 +76,35 @@ public void ConstructorArgumentsAreInheritedIfSpecified()
baracks.Weapon.Should().BeOfType<Sword>();
baracks.Warrior.Weapon.Should().BeOfType<Sword>();
}

#if !MONO
[Fact]
public void WeakConstructorArgument()
{
this.kernel.Bind<IWarrior>().To<Samurai>();
this.kernel.Bind<IWeapon>().To<Dagger>();
this.kernel.Bind<Barracks>().ToSelf().InSingletonScope();

var weakReference = this.Process();

var baracks = this.kernel.Get<Barracks>();

baracks.Weapon.Should().BeOfType<Sword>();
baracks.Warrior.Weapon.Should().BeOfType<Dagger>();
baracks.Weapon.Should().BeSameAs(weakReference.Target);
baracks.Weapon = null;

GC.Collect();

weakReference.IsAlive.Should().BeFalse();
}
#endif

private WeakReference Process()
{
var sword = new Sword();
this.kernel.Get<Barracks>(new WeakConstructorArgument("weapon", sword));
return new WeakReference(sword);
}
}
}
30 changes: 30 additions & 0 deletions src/Ninject.Test/Integration/PropertyInjectionTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
namespace Ninject.Tests.Integration
{
using System;

using FluentAssertions;
using Ninject.Infrastructure.Disposal;
using Ninject.Parameters;
Expand Down Expand Up @@ -74,6 +76,34 @@ public void PropertyValuesOverrideDefaultBinding()
ValidateNinjaWarriorWithOverides(warrior);
}
#endif //!SILVERLIGHT

#if !MONO
[Fact]
public void WeakPropertyValue()
{
this.kernel.Bind<FootSoldier>().ToSelf().InSingletonScope();
this.kernel.Bind<IWeapon>().To<Dagger>();

var weakReference = this.Process();

var warrior = this.kernel.Get<FootSoldier>();

warrior.Weapon.Should().BeOfType<Sword>();
warrior.Weapon.Should().BeSameAs(weakReference.Target);
warrior.Weapon = null;

GC.Collect();

weakReference.IsAlive.Should().BeFalse();
}
#endif

private WeakReference Process()
{
var sword = new Sword();
this.kernel.Get<FootSoldier>(new WeakPropertyValue("Weapon", sword));
return new WeakReference(sword);
}
}

public class WhenNoPropertyOverridesAreSupplied : PropertyInjectionTests
Expand Down
10 changes: 6 additions & 4 deletions src/Ninject.Test/Ninject.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,13 @@
</Reference>
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
<Reference Include="xunit, Version=1.1.0.1323, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
<Reference Include="xunit, Version=1.9.1.1600, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\tools\xunit.net\xunit.dll</HintPath>
<HintPath>..\..\packages\xunit.1.9.1\lib\net20\xunit.dll</HintPath>
</Reference>
<Reference Include="xunit.extensions">
<HintPath>..\..\tools\xunit.net\xunit.extensions.dll</HintPath>
<Reference Include="xunit.extensions, Version=1.9.1.1600, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\packages\xunit.extensions.1.9.1\lib\net20\xunit.extensions.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
Expand Down Expand Up @@ -156,6 +157,7 @@
<Compile Include="Integration\SingletonScopeTests.cs" />
<Compile Include="Integration\ActivationScopeTests.cs" />
<Compile Include="Unit\TestObject.cs" />
<None Include="packages.config" />
<None Include="TestModules\test.bar">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
Expand Down
5 changes: 5 additions & 0 deletions src/Ninject.Test/packages.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="xunit" version="1.9.1" targetFramework="net40" />
<package id="xunit.extensions" version="1.9.1" targetFramework="net40" />
</packages>
38 changes: 17 additions & 21 deletions src/Ninject/Activation/Strategies/PropertyInjectionStrategy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ private BindingFlags Flags
/// <param name="injectorFactory">The injector factory component.</param>
public PropertyInjectionStrategy(IInjectorFactory injectorFactory)
{
InjectorFactory = injectorFactory;
this.InjectorFactory = injectorFactory;
}

/// <summary>
Expand All @@ -67,43 +67,38 @@ public override void Activate(IContext context, InstanceReference reference)
Ensure.ArgumentNotNull(context, "context");
Ensure.ArgumentNotNull(reference, "reference");

var propertyValues = context.Parameters.Where(parameter => parameter is PropertyValue);
IEnumerable<string> parameterNames = propertyValues.Select(parameter => parameter.Name);
var propertyValues = context.Parameters.OfType<IPropertyValue>().ToList();

foreach (var directive in context.Plan.GetAll<PropertyInjectionDirective>())
{
PropertyInjectionDirective propertyInjectionDirective = directive;
if (parameterNames.Any(name => string.Equals(name, propertyInjectionDirective)))
continue;

object value = GetValue(context, directive.Target);
object value = this.GetValue(context, directive.Target, propertyValues);
directive.Injector(reference.Instance, value);
}

AssignProperyOverrides( context, reference, propertyValues );
this.AssignProperyOverrides(context, reference, propertyValues);
}

/// <summary>
/// Applies user supplied override values to instance properties.
/// </summary>
/// <param name="context">The context.</param>
/// <param name="reference">A reference to the instance being activated.</param>
/// <param name="propertyValues">The parameter ovverride value accessors.</param>
private void AssignProperyOverrides( IContext context, InstanceReference reference, IEnumerable<IParameter> propertyValues )
/// <param name="propertyValues">The parameter override value accessors.</param>
private void AssignProperyOverrides(IContext context, InstanceReference reference, IList<IPropertyValue> propertyValues)
{
var properties = reference.Instance.GetType().GetProperties( Flags );
var properties = reference.Instance.GetType().GetProperties(this.Flags);
foreach (var propertyValue in propertyValues)
{
string propertyName = propertyValue.Name;
var propertyInfo = properties
.Where(property => string.Equals(property.Name, propertyName, StringComparison.Ordinal))
.FirstOrDefault();
var propertyInfo = properties.FirstOrDefault(property => string.Equals(property.Name, propertyName, StringComparison.Ordinal));

if(propertyInfo == null)
if (propertyInfo == null)
{
throw new ActivationException(ExceptionFormatter.CouldNotResolvePropertyForValueInjection(context.Request, propertyName));

var target = new PropertyInjectionDirective( propertyInfo, InjectorFactory.Create( propertyInfo ) );
object value = GetValue(context, target.Target);
}

var target = new PropertyInjectionDirective(propertyInfo, this.InjectorFactory.Create(propertyInfo));
object value = this.GetValue(context, target.Target, propertyValues);
target.Injector(reference.Instance, value);
}
}
Expand All @@ -113,13 +108,14 @@ private void AssignProperyOverrides( IContext context, InstanceReference referen
/// </summary>
/// <param name="context">The context.</param>
/// <param name="target">The target.</param>
/// <param name="allPropertyValues">all property values of the current request.</param>
/// <returns>The value to inject into the specified target.</returns>
public object GetValue(IContext context, ITarget target)
private object GetValue(IContext context, ITarget target, IEnumerable<IPropertyValue> allPropertyValues)
{
Ensure.ArgumentNotNull(context, "context");
Ensure.ArgumentNotNull(target, "target");

var parameter = context.Parameters.OfType<PropertyValue>().Where(p => p.Name == target.Name).SingleOrDefault();
var parameter = allPropertyValues.SingleOrDefault(p => p.Name == target.Name);
return parameter != null ? parameter.GetValue(context, target) : target.ResolveWithin(context);
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/Ninject/Ninject.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@
<Compile Include="Infrastructure\Language\ExtensionsForMemberInfo.cs" />
<Compile Include="Infrastructure\ReferenceEqualWeakReference.cs" />
<Compile Include="Parameters\IConstructorArgument.cs" />
<Compile Include="Parameters\IPropertyValue.cs" />
<Compile Include="Parameters\WeakConstructorArgument.cs" />
<Compile Include="Parameters\WeakPropertyValue.cs" />
<Compile Include="Planning\Bindings\BindingBuilder.cs" />
<Compile Include="Planning\Bindings\BindingConfiguration.cs" />
<Compile Include="Planning\Bindings\BindingConfigurationBuilder.cs" />
Expand Down
30 changes: 30 additions & 0 deletions src/Ninject/Parameters/IPropertyValue.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//-------------------------------------------------------------------------------
// <copyright file="IPropertyValue.cs" company="Ninject Project Contributors">
// Copyright (c) 2009-2013 Ninject Project Contributors
// Authors: Remo Gloor (remo.gloor@gmail.com)
//
// Dual-licensed under the Apache License, Version 2.0, and the Microsoft Public License (Ms-PL).
// you may not use this file except in compliance with one of the Licenses.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
// or
// http://www.microsoft.com/opensource/licenses.mspx
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>
//-------------------------------------------------------------------------------

namespace Ninject.Parameters
{
/// <summary>
/// Overrides the injected value of a property.
/// </summary>
public interface IPropertyValue : IParameter
{
}
}
2 changes: 1 addition & 1 deletion src/Ninject/Parameters/Parameter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public class Parameter : IParameter
/// <summary>
/// Gets or sets the callback that will be triggered to get the parameter's value.
/// </summary>
public Func<IContext, ITarget, object> ValueCallback { get; private set; }
public Func<IContext, ITarget, object> ValueCallback { get; internal set; }

/// <summary>
/// Initializes a new instance of the <see cref="Parameter"/> class.
Expand Down
2 changes: 1 addition & 1 deletion src/Ninject/Parameters/PropertyValue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ namespace Ninject.Parameters
/// <summary>
/// Overrides the injected value of a property.
/// </summary>
public class PropertyValue : Parameter
public class PropertyValue : Parameter, IPropertyValue
{
/// <summary>
/// Initializes a new instance of the <see cref="PropertyValue"/> class.
Expand Down
Loading

0 comments on commit 88fcb06

Please sign in to comment.