I am trying to use Ninject to implement cascading injection into a class that contains an IList field. It seems that, unless I specifically specify each binding to use in the kernel.Get method, the IList property is always injected with a list of a single default object.
The following VSTest code illustrates the problem. The first test fails because the IList field contains one MyType object with Name=null. The second test passes, but I had to specifically tell Ninject what constructor arguments to use. I am using the latest build from the ninject.web.mvc project for MVC 3.
Does Ninject specifically treat IList different, or is there a better way to handle this? Note that this seems to only be a problem when using an IList. Createing a custom collection object that wraps IList works as expected in the first test.
[TestClass()]
public class NinjectTest
{
[TestMethod()]
public void ListTest_Fails_NameNullAndCountIncorrect()
{
var kernel = new Ninject.StandardKernel(new MyNinjectModule());
var target = kernel.Get<MyModel>();
var actual = target.GetList();
// Fails. Returned value is set to a list of a single object equal to default(MyType)
Assert.AreEqual(2, actual.Count());
// Fails because MyType object is initialized with a null "Name" property
Assert.AreEqual("Fred", actual.First().Name);
}
[TestMethod()]
public void ListTest_Passes_SeemsLikeUnnecessaryConfiguration()
{
var kernel = new Ninject.StandardKernel(new MyNinjectModule());
var target = kernel.Get<MyModel>(new ConstructorArgument("myGenericObject", kernel.Get<IGenericObject<MyType>>(new ConstructorArgument("myList", kernel.Get<IList<MyType>>()))));
var actual = target.GetList();
Assert.AreEqual(2, actual.Count());
Assert.AreEqual("Fred", actual.First().Name);
}
}
public class MyNinjectModule : NinjectModule
{
public override void Load()
{
Bind<IList<MyType>>().ToConstant(new List<MyType> { new MyType { Name = "Fred" }, new MyType { Name = "Bob" } });
Bind<IGenericObject<MyType>>().To<StubObject<MyType>>();
}
}
public class MyModel
{
private IGenericObject<MyType> myGenericObject;
public MyModel(IGenericObject<MyType> myGenericObject)
{
this.myGenericObject = myGenericObject;
}
public IEnumerable<MyType> GetList()
{
return myGenericObject.GetList();
}
}
public interface IGenericObject<T>
{
IList<T> GetList();
}
public class StubObject<T> : IGenericObject<T>
{
private IList<T> _myList;
public StubObject(IList<T> myList)
{
_myList = myList;
}
public IList<T> GetList()
{
return _myList;
}
}
public class MyType
{
public String Name { get; set; }
}
lists, collections and arrays are handled slightly different. For those types ninject will inject a list or array containing an instance of all bindings for the generic type. In your case the implementation type is a class which is aoutobound by default. So the list will contain one instance of that class. If you add an interface to that class and use this one the list will be empty.
Related
With a simple class/interface like this
public interface IThing
{
string Name { get; set; }
}
public class Thing : IThing
{
public int Id { get; set; }
public string Name { get; set; }
}
How can I get the JSON string with only the "Name" property (only the properties of the underlying interface) ?
Actually, when i make that :
var serialized = JsonConvert.SerializeObject((IThing)theObjToSerialize, Formatting.Indented);
Console.WriteLine(serialized);
I get the full object as JSON (Id + Name);
The method I use,
public class InterfaceContractResolver : DefaultContractResolver
{
private readonly Type _InterfaceType;
public InterfaceContractResolver (Type InterfaceType)
{
_InterfaceType = InterfaceType;
}
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
//IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization);
IList<JsonProperty> properties = base.CreateProperties(_InterfaceType, memberSerialization);
return properties;
}
}
// To serialize do this:
var settings = new JsonSerializerSettings() {
ContractResolver = new InterfaceContractResolver (typeof(IThing))
};
string json = JsonConvert.SerializeObject(theObjToSerialize, settings);
Improved version with nested interfaces + support for xsd.exe objects
Yet another variation here. The code came from http://www.tomdupont.net/2015/09/how-to-only-serialize-interface.html with the following improvements over other answers here
Handles hierarchy, so if you have an Interface2[] within an Interface1 then it will get serialized.
I was trying to serialize a WCF proxy object and the resultant JSON came up as {}. Turned out all properties were set to Ignore=true so I had to add a loop to set them all to not being ignored.
public class InterfaceContractResolver : DefaultContractResolver
{
private readonly Type[] _interfaceTypes;
private readonly ConcurrentDictionary<Type, Type> _typeToSerializeMap;
public InterfaceContractResolver(params Type[] interfaceTypes)
{
_interfaceTypes = interfaceTypes;
_typeToSerializeMap = new ConcurrentDictionary<Type, Type>();
}
protected override IList<JsonProperty> CreateProperties(
Type type,
MemberSerialization memberSerialization)
{
var typeToSerialize = _typeToSerializeMap.GetOrAdd(
type,
t => _interfaceTypes.FirstOrDefault(
it => it.IsAssignableFrom(t)) ?? t);
var props = base.CreateProperties(typeToSerialize, memberSerialization);
// mark all props as not ignored
foreach (var prop in props)
{
prop.Ignored = false;
}
return props;
}
}
Inspired by #user3161686, here's a small modification to InterfaceContractResolver:
public class InterfaceContractResolver<TInterface> : DefaultContractResolver where TInterface : class
{
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
IList<JsonProperty> properties = base.CreateProperties(typeof(TInterface), memberSerialization);
return properties;
}
}
You can use conditional serialization. Take a look at this link. Basicly, you need to implement the IContractResolver interface, overload the ShouldSerialize method and pass your resolver to the constructor of the Json Serializer.
An alternative to [JsonIgnore] are the [DataContract] and [DataMember] attributes. If you class is tagged with [DataContract] the serializer will only process properties tagged with the [DataMember] attribute (JsonIgnore is an "opt-out" model while DataContract is "op-in").
[DataContract]
public class Thing : IThing
{
[DataMember]
public int Id { get; set; }
public string Name { get; set; }
}
The limitation of both approaches is that they must be implemented in the class, you cannot add them to the interface definition.
You can add the [JsonIgnore] annotation to ignore an attribute.
I'd like to share what we ended up doing when confronted with this task. Given the OP's interface and class...
public interface IThing
{
string Name { get; set; }
}
public class Thing : IThing
{
public int Id { get; set; }
public string Name { get; set; }
}
...we created a class that is the direct implementation of the interface...
public class DirectThing : IThing
{
public string Name { get; set; }
}
Then simply serialized our Thing instance, deserialized it as a DirectThing, then Serialized it as a DirectThing:
var thing = new Thing();
JsonConvert.SerializeObject(
JsonConvert.DeserializeObject<DirectThing>(JsonConvert.SerializeObject(thing)));
This approach can work with a long interface inheritance chain...you just need to make a direct class (DirectThing in this example) at the level of interest. No need to worry about reflection or attributes.
From a maintenance perspective, the DirectThing class is easy to maintain if you add members to IThing because the compiler will give errors if you haven't also put them in DirectThing. However, if you remove a member X from IThing and put it in Thing instead, then you'll have to remember to remove it from DirectThing or else X would be in the end result.
From a performance perspective there are three (de)serialization operations happening here instead of one, so depending on your situation you might like to evaluate the performance difference of reflector/attribute-based solutions versus this solution. In my case I was just doing this on a small scale, so I wasn't concerned about potential losses of some micro/milliseconds.
Hope that helps someone!
in addition to the answer given by #monrow you can use the default [DataContract] and [DataMember]
have a look at this
http://james.newtonking.com/archive/2009/10/23/efficient-json-with-json-net-reducing-serialized-json-size.aspx
Finally I got when it will not work...
If you want to have inside another complex object it will not be properly serialized.
So I have made version which will extract only data stored in specific assembly and for types which have the same base interface.
So it is made as .Net Core JsonContractResolver.
In addition to data extraction it solves:
a) camelCase conversion before sending data to client
b) uses top most interface from allowed scope (by assembly)
c) fixes order of fields: field from most base class will be listed first and nested object will meet this rule as well.
public class OutputJsonResolver : DefaultContractResolver
{
#region Static Members
private static readonly object syncTargets = new object();
private static readonly Dictionary<Type, IList<JsonProperty>> Targets = new Dictionary<Type, IList<JsonProperty>>();
private static readonly Assembly CommonAssembly = typeof(ICommon).Assembly;
#endregion
#region Override Members
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
if (type.Assembly != OutputJsonResolver.CommonAssembly)
return base.CreateProperties(type, memberSerialization);
IList<JsonProperty> properties;
if (OutputJsonResolver.Targets.TryGetValue(type, out properties) == false)
{
lock (OutputJsonResolver.syncTargets)
{
if (OutputJsonResolver.Targets.ContainsKey(type) == false)
{
properties = this.CreateCustomProperties(type, memberSerialization);
OutputJsonResolver.Targets[type] = properties;
}
}
}
return properties;
}
protected override string ResolvePropertyName(string propertyName)
{
return propertyName.ToCase(Casing.Camel);
}
#endregion
#region Assistants
private IList<JsonProperty> CreateCustomProperties(Type type, MemberSerialization memberSerialization)
{
// Hierarchy
IReadOnlyList<Type> types = this.GetTypes(type);
// Head
Type head = types.OrderByDescending(item => item.GetInterfaces().Length).FirstOrDefault();
// Sources
IList<JsonProperty> sources = base.CreateProperties(head, memberSerialization);
// Targets
IList<JsonProperty> targets = new List<JsonProperty>(sources.Count);
// Repository
IReadOnlyDistribution<Type, JsonProperty> repository = sources.ToDistribution(item => item.DeclaringType);
foreach (Type current in types.Reverse())
{
IReadOnlyPage<JsonProperty> page;
if (repository.TryGetValue(current, out page) == true)
targets.AddRange(page);
}
return targets;
}
private IReadOnlyList<Type> GetTypes(Type type)
{
List<Type> types = new List<Type>();
if (type.IsInterface == true)
types.Add(type);
types.AddRange(type.GetInterfaces());
return types;
}
#endregion
}
I have a class with a collection that needs validation. The generic on the collection takes an interface and different types can be added to the collection.
What is the cleanest path forward to creating a FluentValidation validator that supports polymorphism?
public interface IWizardStep {}
public class WizardOne : IWizardStep
{
public string Model { get; set; }
}
public class WizardTwo : IWizardStep
{
public string FirstName { get; set; }
}
public class Wizard
{
public Wizard()
{
var w1 = new WizardOne();
var w2 = new WizardTwo();
Steps = new List<IWizardStep>
{
w1,
w2
};
}
public IList<IWizardStep> Steps { get; set; }
}
public class WizardValidator : AbstractValidator<Wizard>
{
public WizardValidator()
{
RuleFor(x => x.Steps)
// Steps First where is WizardOne
// Model.NotEmpty()
// Steps First where is WizardTwo
// FirstName.NotEmpty()
}
FluentValidation doesn't support polymorphism for child collections like this out of the box, but you can add this behaviour by using a custom property validator, or by using OfType in your rule definitions.
I've written about both approaches before here:
Step 1: Create a validator for each implementor
Start by creating a validator for WizardOne and WizardTwo:
public class WizardOneValidator : AbstractValidator<WizardOne> {
public WizardOneValidator() {
RuleFor(x => x.Model).NotEmpty();
}
}
public class WizardTwoValidator : AbstractValidator<WizardTwo> {
public WizardTwoValidator() {
RuleFor(x => x.FirstName).NotEmpty();
}
}
Step 2: Create the parent validator
You have two options for defining the parent validator. The simplest approach is to use OfType, but this is less performant. The more complex option is to use a custom property validator.
Option 1: Using OfType
public WizardValidator : AbstractValidator<Wizard> {
public WizardValidator() {
RuleForEach(x => x.Steps.OfType<WizardOne>()).SetValidator(new WizardOneValidator());
RuleForEach(x => x.Steps.OfType<WizardTwo>()).SetValidator(new WizardTwoValidator());
}
}
This is the simplest approach, but calling OfType inside the call RuleFor will end up bypassing FluentValidation's expression cache, which is a potential performance hit. It also iterates the collection multiple. This may or may not be an issue for you - you'll need to decide if this has any real-world impact on your application.
Option 2: Using a custom PropertyValidator.
This uses a custom custom validator which can differentiate the underlying type at runtime:
public WizardValidator : AbstractValidator<Wizard> {
public WizardValidator() {
RuleForEach(x => x.Steps).SetValidator(new PolymorphicValidator<Wizard, IWizardStep>()
.Add<WizardOne>(new WizardOneValidator())
.Add<WizardTwo>(new WizardTwoValidator())
);
}
}
Syntactically, this isn't quite as nice, but doesn't bypass the expression cache and doesn't iterate the collection multiple times. This is the code for the PolymorphicValidator:
public class PolymorphicValidator<T, TInterface> : ChildValidatorAdaptor<T, TInterface> {
readonly Dictionary<Type, IValidator> _derivedValidators = new Dictionary<Type, IValidator>();
// Need the base constructor call, even though we're just passing null.
public PolymorphicValidator() : base((IValidator<TInterface>)null, typeof(IValidator<TInterface>)) {
}
public PolymorphicValidator<T, TInterface> Add<TDerived>(IValidator<TDerived> derivedValidator) where TDerived : TInterface {
_derivedValidators[typeof(TDerived)] = derivedValidator;
return this;
}
public override IValidator<TInterface> GetValidator(PropertyValidatorContext context) {
// bail out if the current item is null
if (context.PropertyValue == null) return null;
if (_derivedValidators.TryGetValue(context.PropertyValue.GetType(), out var derivedValidator)) {
return new ValidatorWrapper(derivedValidator);
}
return null;
}
private class ValidatorWrapper : AbstractValidator<TInterface> {
private IValidator _innerValidator;
public ValidatorWrapper(IValidator innerValidator) {
_innerValidator = innerValidator;
}
public override ValidationResult Validate(ValidationContext<TInterface> context) {
return _innerValidator.Validate(context);
}
public override Task<ValidationResult> ValidateAsync(ValidationContext<TInterface> context, CancellationToken cancellation = new CancellationToken()) {
return _innerValidator.ValidateAsync(context, cancellation);
}
public override IValidatorDescriptor CreateDescriptor() {
return _innerValidator.CreateDescriptor();
}
}
}
This will probably be implemented in the library as a first class feature at some point in the future - you can track its development here if you're interested.
I've created this code:
public class AddonsModule : Ninject.Modules.NinjectModule
{
public override void Load()
{
this.Bind(b => b.FromAssembliesMatching("*")
.SelectAllClasses()
.InheritedFrom(typeof(UIExtensibility.AbstractAddon))
.BindWith(new AddonBindingGenerator())
);
}
private class AddonBindingGenerator : IBindingGenerator
{
public System.Collections.Generic.IEnumerable<Ninject.Syntax.IBindingWhenInNamedWithOrOnSyntax<object>> CreateBindings(System.Type type, Ninject.Syntax.IBindingRoot bindingRoot)
{
if (type.IsInterface || type.IsAbstract)
yield break;
yield return bindingRoot.Bind(type).ToProvider(typeof(UIExtensibility.AbstractAddon));
}
}
private class AddonProvider : IProvider<UIExtensibility.AbstractAddon>
{
public object Create(IContext context)
{
return null;
}
public Type Type
{
get { throw new NotImplementedException(); }
}
}
}
AddonProvider seems be avoided. This is never performed.
When I perform:
kernel.GetAll<UIExtensibility.AbstractAddon>(), AddonProvider.Create method is never performed.
Could you tell me what's wrong?
I'll appreciate a lot your help.
Thanks for all.
AddOnProvider is inheriting from IProvider<T> instead of UIExtensibility.AbstractAddon.
also, you may have issues binding to private inner classes. make AddOnProvider a public top level class.
You're binding a specific type which inherits from typeof(UIExtensibility.AbstractAddon) to a provider. For example, there could be a class Foo : UIExtensibility.AbstractAddon.
Now your convention binding translates to this:
Bind<Foo>().ToProvider<AddonProvider>();
Now, kernel.GetAll<UIExtensibility.AbstractAddon>() however is looking for bindings made like:
Bind<UIExtensibility.AbstractAddon>().To...
Fix It
So what you need to do is change the line
bindingRoot.Bind(type).ToProvider(new AddonProvider());
to:
bindingRoot.Bind(typeof(UIExtensibility.AbstractAddon)).ToProvider<AddonProvider>();
Furthermore
you're line object f = bindingRoot.Bind(type).ToProvider(new AddonProvider()); is never returning the binding (object f).
does UIExtensibility.AbstractAddon implement IProvider?
Thanks for your answer and comments.
I believe the trouble is on I'm not quite figuring out how this "generic" binding process works.
I'm going to try writing my brain steps process out:
I need to bind every AbstractAddon implementation inside addons assemblies folder. So, I think this code is right, but I'm not sure at all.
this.Bind(b => b.FromAssembliesMatching("*")
.SelectAllClasses()
.InheritedFrom(typeof(UIExtensibility.AbstractAddon))
.BindWith(new AddonBindingGenerator())
);
My AbstractAddon is like:
public abstract class AbstractAddon : IAddon
{
private object configuration;
public AbstractAddon(object configuration)
{
this.configuration = configuration;
}
// IAddon interface
public abstract string PluginId { get; }
public abstract string PluginVersion { get; }
public abstract string getCaption(string key);
public abstract Type getConfigurationPanelType();
public abstract System.Windows.Forms.UserControl createConfigurationPanel();
}
I guess I need to:
foreach implementation of `AbstractAddon` found out,
I need to "inject" a configuration object ->
So, I guess I need to set a provider and provide this configuration object.
This would be my main way of thinking in order to solve this problem.
I've changed a bit my first approach. Instead of using a IBindingGenerator class, I've used the next:
public class AddonsModule : Ninject.Modules.NinjectModule
{
public override void Load()
{
this.Bind(b => b.FromAssembliesMatching("*")
.SelectAllClasses()
.InheritedFrom(typeof(UIExtensibility.AbstractAddon))
.BindAllBaseClasses()
.Configure(c => c.InSingletonScope())
);
this.Bind<object>().ToProvider<ConfigurationProvider>()
.WhenTargetHas<UIExtensibility.ConfigurationAttribute>();
}
So, My ConfigurationProvider is:
private class ConfigurationProvider : IProvider<object>
{
public object Create(IContext context)
{
return "configuration settings";
}
}
And now, my AbstractAddon constructor contains the parameter annotated with ConfigurationAttribute as:
public AbstractAddon([Configuration]object configuration)
{
this.configuration = configuration;
}
The problem now, NInject seems to ignore the configuration object provider. NInject generates a dump object, however, not perform ConfigurationProvider.Create method...
What I'm doing wrong, now?
Is this approach really better than the last one?
Thanks for all.
I have a class I am unit testing and all I want to do is to verify that the public setter gets called on the property. Any ideas on how to do this?
I don't want to check that a value was set to prove that it was called. I only want to ensure that the constructor is using the public setter . Note that this property data type is a primitive string
This is not the sort of scenario that mocking is designed for because you are trying to test an implementation detail. Now if this property was on a different class that the original class accessed via an interface, you would mock that interface and set an expectation with the IgnoreArguments syntax:
public interface IMyInterface
{
string MyString { get; set; }
}
public class MyClass
{
public MyClass(IMyInterface argument)
{
argument.MyString = "foo";
}
}
[TestClass]
public class Tests
{
[TestMethod]
public void Test()
{
var mock = MockRepository.GenerateMock<IMyInterface>();
mock.Expect(m => m.MyString = "anything").IgnoreArguments();
new MyClass(mock);
mock.VerifyAllExpectations();
}
}
There are 2 problems with what you are trying to do. The first is that you are trying to mock a concrete class, so you can only set expectations if the properties are virtual.
The second problem is the fact that the event that you want to test occurs in the constructor, and therefore occurs when you create the mock, and so occurs before you can set any expectations.
If the class is not sealed, and the property is virtual, you can test this without mocks by creating your own derived class to test with such as this:
public class RealClass
{
public virtual string RealString { get; set; }
public RealClass()
{
RealString = "blah";
}
}
[TestClass]
public class Tests
{
private class MockClass : RealClass
{
public bool WasStringSet;
public override string RealString
{
set { WasStringSet = true; }
}
}
[TestMethod]
public void Test()
{
MockClass mockClass = new MockClass();
Assert.IsTrue(mockClass.WasStringSet);
}
}
I have a base abstract class, which aggregates a bunch of items in a collection:
abstract class AMyAbstract
{
List<string> Items { get; private set; }
public AMyAbstract(IEnumerable<string> items)
{
this.Items = new List<string>(items);
}
}
There are a lot of subclasses, let's name them Foo, Bar, Baz, etc. They all are immutable. Now I need a merge() method, which will merge items of two objects like this:
abstract class AMyAbstract
{
// ...
public AMyAbstract merge(AMyAbstract other)
{
// how to implement???
}
}
Foo foo1 = new Foo(new string[] {"a", "b"});
Bar bar1 = new Bar(new string[] {"c", "d"});
Foo fooAndBar = foo1.merge(bar1);
// items in fooAndBar now contain: {"a", "b", "c", "d"}
Since the objects are immutable, the merge() method should not change the state of items field, but instead it should return a new object of the class uppon which it is called. My question is: how to judiciously implement the merge() method?
Problem 1: AMyAbstract is clearly not aware of specific constructors of the subclasses (dependency inversion principle), thus I cannot (or can I?) create instance of the sub class in a super class.
Problem 2: Implementing merge() method in each of the subclasses is a lot of code repetition (DRY rule).
Problem 3: Extracting the merge() logic to a entirely new class does not solve the DRY rule problem. Even using the visitor pattern it is a lot of copy/paste.
The problems presented above rule out any idea of implementation I might have had before I read about SOLID. (my life has been miserable since then ;)
Or is there an entirely different, out-of-the-box approch to achieve the merge of such objects?
I'd appreciate answer in C#, Java or even PHP.
EDIT: I think I left out a piece of valid information: event though there are a lot of different sub classes, they can (should) only be constructed in two, maybe three ways (as an implication of the single responsibility principle):
parameterless constructor
a constructor which accepts one IEnumerable<T> argument
a constructor which accepts array and some other modifier
This would put the visitor pattern back on the tablie if I could put a constraint on the constructors - for example by defining a constructor in an interface. But this is possible only in PHP. In Java or C# a constructor signature cannot be enforced, thus I cannot be certain of how I would instantiate a subclass. This is a good rule in general, because one could never predict of how author of the subclass would like the object be constructed, but in this particular case it might have been helpful. So a helper question would be: can I somehow enforce how a class is instantiated? Builder pattern sounds like way too much in this simple case, or does it?
You are right about dependency inversion rule and code duplication problems.
You can write the core implementation of the merge logic in your abstract class and give out the task of creating a new instance to the derived classes. Create an abstract method in your abstract class that will force all the children to implement it. The purpose is this method is to create a new instance of the class and return it. This method will be used by the super class to get a new instance and do the merging.
The resultant java code will look something like this
abstract class AMyAbstract {
// ...
public AMyAbstract merge(AMyAbstract other) {
AMyAbstract obj = getNewInstance();
// Do the merge
// Return the merged object.
}
protected abstract AMyAbstract getNewInstance();
}
class foo extends AMyAbstract {
protected foo getNewInstance() {
// Instantiate Foo and return it.
}
}
Hope this helps..
OBSOLETE, kept for reference (and shows how I arrived at the final solution), see code after EDIT below
I would say the builder pattern is the way to go. We just need a builder which keeps the instance but modifies the one field that needs to be changed.
If one wants to obtain (as shown in your code)
Foo fooAndBar = foo1.merge(bar1);
an additional generic type definition is needed (thus defining class AMyAbstract <T>) to be able to still produce the correct final type (instead of just seeing AMyAbstract as type for the fooAndBar) in the above call.
Note: merge method was renamed to MergeItems in the code below to make clear what is merged.
I specified different constructors for Foo and Bar, so that it is clear that they do not need to have the same number of parameters.
Actually to be truly immutable, the list should not be directly returned in the Items property as it could be modified by the caller (using new List(items).AsReadOnly() produced a ReadOnlyCollection, so I just used this one).
Code:
abstract class AMyAbstract<T> where T : AMyAbstract<T>
{
public ReadOnlyCollection<string> Items { get; private set; }
protected AMyAbstract(IEnumerable<string> items)
{
this.Items = new List<string>(items).AsReadOnly();
}
public T MergeItems<T2>(AMyAbstract<T2> other) where T2 : AMyAbstract<T2>
{
List<string> mergedItems = new List<string>(Items);
mergedItems.AddRange(other.Items);
ButWithItemsBuilder butWithItemsBuilder = GetButWithItemsBuilder();
return butWithItemsBuilder.ButWithItems(mergedItems);
}
public abstract class ButWithItemsBuilder
{
public abstract T ButWithItems(List<string> items);
}
public abstract ButWithItemsBuilder GetButWithItemsBuilder();
}
class Foo : AMyAbstract<Foo>
{
public string Param1 { get; private set; }
public Foo(IEnumerable<string> items, string param1)
: base(items)
{
this.Param1 = param1;
}
public class FooButWithItemsBuilder : ButWithItemsBuilder
{
private readonly Foo _foo;
internal FooButWithItemsBuilder(Foo foo)
{
this._foo = foo;
}
public override Foo ButWithItems(List<string> items)
{
return new Foo(items, _foo.Param1);
}
}
public override ButWithItemsBuilder GetButWithItemsBuilder()
{
return new FooButWithItemsBuilder(this);
}
}
class Bar : AMyAbstract<Bar>
{
public string Param2 { get; private set; }
public int Param3 { get; private set; }
public Bar(IEnumerable<string> items, string param2, int param3)
: base(items)
{
this.Param2 = param2;
this.Param3 = param3;
}
public class BarButWithItemsBuilder : ButWithItemsBuilder
{
private readonly Bar _bar;
internal BarButWithItemsBuilder(Bar bar)
{
this._bar = bar;
}
public override Bar ButWithItems(List<string> items)
{
return new Bar(items, _bar.Param2, _bar.Param3);
}
}
public override ButWithItemsBuilder GetButWithItemsBuilder()
{
return new BarButWithItemsBuilder(this);
}
}
class Program
{
static void Main()
{
Foo foo1 = new Foo(new[] { "a", "b" }, "param1");
Bar bar1 = new Bar(new[] { "c", "d" }, "param2", 3);
Foo fooAndBar = foo1.MergeItems(bar1);
// items in fooAndBar now contain: {"a", "b", "c", "d"}
Console.WriteLine(String.Join(", ", fooAndBar.Items));
Console.ReadKey();
}
}
EDIT
Perhaps a simpler solution would be to avoid the builder class, and instead have
abstract T ButWithItems(List<string> items);
directly in the base class, and implementing classes would just implement it as currently the builders do.
Code:
abstract class AMyAbstract<T> where T : AMyAbstract<T>
{
public ReadOnlyCollection<string> Items { get; private set; }
protected AMyAbstract(IEnumerable<string> items)
{
this.Items = new List<string>(items).AsReadOnly();
}
public T MergeItems<T2>(AMyAbstract<T2> other) where T2 : AMyAbstract<T2>
{
List<string> mergedItems = new List<string>(Items);
mergedItems.AddRange(other.Items);
return ButWithItems(mergedItems);
}
public abstract T ButWithItems(List<string> items);
}
class Foo : AMyAbstract<Foo>
{
public string Param1 { get; private set; }
public Foo(IEnumerable<string> items, string param1)
: base(items)
{
this.Param1 = param1;
}
public override Foo ButWithItems(List<string> items)
{
return new Foo(items, Param1);
}
}
class Bar : AMyAbstract<Bar>
{
public string Param2 { get; private set; }
public int Param3 { get; private set; }
public Bar(IEnumerable<string> items, string param2, int param3)
: base(items)
{
this.Param2 = param2;
this.Param3 = param3;
}
public override Bar ButWithItems(List<string> items)
{
return new Bar(items, Param2, Param3);
}
}
class Program
{
static void Main()
{
Foo foo1 = new Foo(new[] { "a", "b" }, "param1");
Bar bar1 = new Bar(new[] { "c", "d" }, "param2", 3);
Foo fooAndBar = foo1.MergeItems(bar1);
// items in fooAndBar now contain: {"a", "b", "c", "d"}
Console.WriteLine(String.Join(", ", fooAndBar.Items));
Console.ReadKey();
}
}
I'm a bit late to the party but as you have yet to accept an answer I thought I would add my own.
One of the key points is that the collection should be immutable. In my example I have exposed IEnumerable to facilitate this - the collection of items is immutable outside of the instance.
There are 2 ways I see this working:
a public default constructor
an internal Clone template method similar to #naveen's answer above
Option 1 is less code but really it depends whether an instance of AMyAbstract with no items and no way to change the items is something you want to allow.
private readonly List<string> items;
public IEnumerable<string> Items { get { return this.items; } }
public static T CreateMergedInstance<T>(T from, AMyAbstract other)
where T : AMyAbstract, new()
{
T result = new T();
result.items.AddRange(from.Items);
result.items.AddRange(other.Items);
return result;
}
Seems to satisfy all of your requirements
[Test]
public void MergeInstances()
{
Foo foo = new Foo(new string[] {"a", "b"});
Bar bar = new Bar(new string[] {"c", "d"});
Foo fooAndBar = Foo.CreateMergedInstance(foo, bar);
Assert.That(fooAndBar.Items.Count(), Is.EqualTo(4));
Assert.That(fooAndBar.Items.Contains("a"), Is.True);
Assert.That(fooAndBar.Items.Contains("b"), Is.True);
Assert.That(fooAndBar.Items.Contains("c"), Is.True);
Assert.That(fooAndBar.Items.Contains("d"), Is.True);
Assert.That(foo.Items.Count(), Is.EqualTo(2));
Assert.That(foo.Items.Contains("a"), Is.True);
Assert.That(foo.Items.Contains("b"), Is.True);
Assert.That(bar.Items.Count(), Is.EqualTo(2));
Assert.That(bar.Items.Contains("c"), Is.True);
Assert.That(bar.Items.Contains("d"), Is.True);
}
Whether you ultimately choose a default constructor or a template method the crux of this answer is that the Items only need to be immutable on the outside.
A neat solution based on #AK_'s comment:
tldr: The basic idea is to create a multiple merge methods for each aggregated filed instead of using a merge method for entire object.
1) we'd want a special list type for the purpose of aggregating the items inside AMyAbstract instances, so let's create one:
class MyList<T> extends ReadOnlyCollection<T> { ... }
abstract class AMyAbstract
{
MyList<string> Items { get; private set; }
//...
}
The advantage here is that we have a specialized list type for our purpose, which we can alter later.
2) instead of having a merge method for entire object of AMyAbstract we would want to use a method which merly merges the items of that object:
abstract class AMyAbstract
{
// ...
MyList<T> mergeList(AMyAbstract other)
{
return this.Items.Concat(other.Items);
}
}
Another advatage we gain: decomposition of the problem of merging entire object. So instead we break it into a small problems (merging just the aggregated list in this case).
3) and now we can create a merged object using any specialized constructor we might think of:
Foo fooAndBar = new Foo(foo1.mergeList(bar1));
Instead of returning the new instance of entire object we return only the merged list, which in turn can be used to create object of target class. Here we gain yet another advantage: deferred object instantiation, which is the main purpose of creational patterns.
SUMMARY:
So not only this solution solves the problems presended in the question, but provides additional advantages presented above.