I have an IContainer called container and I'm trying to add a component to it using the add method. When adding it I get this error
Error 1 The best overloaded method match for
'System.ComponentModel.IContainer.Add(System.ComponentModel.IComponent,
string)' has some invalid
arguments C:\Users\Dan\Source\Workspaces\Bio-Catalysts
repack\Biocats_Repack\itas.s200.biocats.business\SOP\SOPOrderLineVwItems.cs 19 13 itas.s200.biocats.business
Heres the code:
namespace itas.S200.Biocats.Business.SOP
{
using System;
using System.Collections;
using System.ComponentModel;
using Sage.Common.Data;
using Sage.ObjectStore;
public class SOPOrderLineVwItems : PersistentSOPOrderLineVwItems
{
public SOPOrderLineVwItems()
{
}
public SOPOrderLineVwItems(System.ComponentModel.IContainer container)
{
container.Add(this, null);
}
//public SOPOrderLineVwItems(System.Data.IDataReader reader) :
// base(reader)
//{
//}
[System.ComponentModel.DesignerSerializationVisibility(System.ComponentModel.DesignerSerializationVisibility.Hidden)]
public new virtual SOPOrderLineVwItem this[int index]
{
get
{
return ((SOPOrderLineVwItem)(base[index]));
}
set
{
base[index] = value;
}
}
[System.ComponentModel.DesignerSerializationVisibility(System.ComponentModel.DesignerSerializationVisibility.Hidden)]
public override Sage.ObjectStore.PersistentObject Owner
{
get
{
if ((this.Query.Owner == null))
{
this.Query.Owner = new SOPOrderLineVwItem();
}
return this.Query.Owner;
}
}
[System.ComponentModel.DesignerSerializationVisibility(System.ComponentModel.DesignerSerializationVisibility.Hidden)]
public new virtual SOPOrderLineVwItem First
{
get
{
return ((SOPOrderLineVwItem)(base.First));
}
}
}
}
Can provide more code/info if required
Thanks
public class SOPOrderLineVwItems : PersistentSOPOrderLineVwItems, IComponent
IComponent Add() takes a IComponent as argument.
Add
and since you do this
container.Add(this, null);
you need this which is SOPOrderLineVwItems to be an IComponent
Related
=== Problem Solved and the best solution added to the code ===
Hello I have the following problem.
As you can see in the code below I have a command stack that holds commands.
There are more than one types of command and each command class can have a different T parameter although this can only be a class that inherits IModel interface.
And now when I want to check if a certain type of command is currently on the stack. I (until I do something wrong) have to specify the whole type with its template which is very inconvenient as it may lead to a very long if-else statement.
I would like to specify the class type but I do not care about its template type. Is there a way to do it?
Below the whole code that you can just copy and run. It's fully executable and precisely shows what I want to achieve.
using System;
using System.Collections.Generic;
namespace ConsoleApp1
{
public interface IModel { }
class SomeDataModelA : IModel { }
class SomeDataModelB : IModel { }
// in reality there is more models and all of them implements IModel
public interface IUndoRedoCommand
{
void Undo();
void Redo();
}
class RemoveCommand<IModel> : IUndoRedoCommand
{
public void Undo() => throw new NotImplementedException();
public void Redo() => throw new NotImplementedException();
}
class AddCommand<IModel> : IUndoRedoCommand
{
public void Undo() => throw new NotImplementedException();
public void Redo() => throw new NotImplementedException();
}
public class UndoRedoList<T> : List<T>
where T : IModel
{
readonly CommandStack _commandStack;
public UndoRedoList(CommandStack commandStack)
: base()
{
_commandStack = commandStack;
}
public UndoRedoList(int capacity, CommandStack commandStack)
: base(capacity)
{
_commandStack = commandStack;
}
public UndoRedoList(IEnumerable<T> enumerable, CommandStack commandStack)
: base(enumerable)
{
_commandStack = commandStack;
}
public void AddWithUndoRedoTracking(T item)
{
Add(item);
_commandStack.Push(new AddCommand<T>());
}
public void RemoveWithUndoRedoTracking(T item)
{
Remove(item);
_commandStack.Push(new RemoveCommand<T>());
}
public void InsertWithUndoRedoTracking(int index, T item)
=> _commandStack.Push(new AddCommand<T>());
}
public class CommandStack
{
public int UndoCount => _pointer;
public int RedoCount => _undoRedoStack.Count - _pointer;
readonly IList<IUndoRedoCommand> _undoRedoStack = new List<IUndoRedoCommand>();
int _pointer; // points at first redo - so first undo will be _pointer - 1
public void Push(IUndoRedoCommand cmd) => _undoRedoStack.Insert(_pointer++, cmd);
public void Refresh()
{
for (int i = 0; i < _undoRedoStack.Count; i++)
{
IUndoRedoCommand cmd = _undoRedoStack[i];
if (cmd is AddCommand<IModel>)
Console.WriteLine("This doesn't work but it should.");
if(cmd is AddCommand<SomeDataModelA>
|| cmd is AddCommand<SomeDataModelB>
/* and so on for all models*/)
Console.WriteLine("This works but it is ugly.");
// perfect solution by Sweeper
if (cmd.GetType().GetGenericTypeDefinition() == typeof(AddCommand<>))
Console.WriteLine("This works too!! Thank you Sweeper.");
}
}
}
class Program
{
static void Main()
{
var stack = new CommandStack();
var list = new UndoRedoList<SomeDataModelA>(stack);
list.AddWithUndoRedoTracking(new SomeDataModelA());
list.AddWithUndoRedoTracking(new SomeDataModelA());
stack.Refresh();
}
}
}
You can use GetType().GetGenericTypeDefinition(), and compare the types with ==:
if(cmd.GetType().GetGenericTypeDefinition() == typeof(AddCommand<>)) {
}
Note that this won't work if you want subclasses of AddCommand to also enter the if.
My goal is to have a dictionary which stores different Container objects that derive from a interface IContainer. The user can
add different Container objects (as long as they implement IContainer) to this dictionary. The containers can add elements related to the
container (eg configContainer will add configElements, diContainer will add diConfigElements).
The elements also implement from a interface.
I want to avoid the scenario of DiConfigElements being added to ConfigContainer. I have looked at related questions and they dont quite solve my problem.
I feel that generics will solve my problem, I have a example but I get Argument 2: cannot convert from 'ConfigContainer' to 'IContainer'
I am using Unity C#.
test.cs
using System.Collections;
using System.Collections.Generic;
public class test
{
public Dictionary<string, IContainer<IResolveableItem>> containers;
// Use this for initialization
void Start()
{
containers = new Dictionary<string, IContainer<IResolveableItem>>();
ConfigContainer configContainer = new ConfigContainer();
ConfigContainerElement configElement = new ConfigContainerElement();
configElement.Name = "configTest";
configElement.Path = "configTest/configTest";
configContainer.Add("test1", configElement);
containers.Add("config",configContainer);
}
}
IContainer.cs
using System.Collections;
public interface IContainer<T> where T : IResolveableItem
{
void Add(string key , T value);
}
ConfigContainer.cs
using System.Collections.Generic;
public class ConfigContainer : IContainer<ConfigContainerElement>
{
public Dictionary<string, IResolveableItem> container = new Dictionary<string, IResolveableItem>();
public void Add(string key, ConfigContainerElement value)
{
throw new System.NotImplementedException();
}
}
ConfigContainerElement.cs
using System.Collections;
public class ConfigContainerElement : IResolveableItem
{
protected string name;
protected string path;
public string Name
{
get
{
return name;
}
set
{
name = value;
}
}
public string Path
{
get
{
return path;
}
set
{
path = value;
}
}
}
IResolveableItem.cs
using System.Collections;
public interface IResolveableItem
{
string Name { get; set; }
string Path { get; set; }
}
It's a limitation of generics, will have to use runtime checking.
I have the following code:
public interface IMyActionFactory
{
AbstractAction<T> CreateAction<T>(MyActionParamBase paramBase = null)
where T : MyActionParamBase;
}
public sealed class MergeActionParam : MyActionParamBase
{
}
public class MergeTest
{
private readonly IMyActionFactory _actionFactory = new DefaultMyActionFactory();
[Theory]
[PropertyData("MergeWorksData")]
public void MergeWorks(/*params here*/)
{
var param = new MergeActionParam();
// populate param here
var sut = _actionFactory.CreateAction<MergeActionParam>(param);
sut.DoAction();
}
}
I am getting an error
"..Error 10 Using the generic type 'IMyActionFactory' requires 1
type arguments..."
Why does the compiler expect a type to be passed to my IMyActionFactory, since I have declared the interface without a T? As far as the method is concerned its the only one to expect the type. Am I missing something here?
How can I make it work without redefining the interface signature?
EDIT:
Feeling a bit embarassed here, because the quick code I put down and ran seperately in a standalone online c# compiler doesnt give any compilation errors. However, going back to my original solution (tens of projects altogether) the error is still there.. Maybe has something to do with the XUnit ?..not sure
public interface IMyActionFactory
{
AbstractAction<T> CreateAction<T>(MyActionParamBase paramBase = null)
where T : MyActionParamBase;
}
public interface IAction
{
void DoAction();
}
public abstract class AbstractAction<T> : IAction
where T : MyActionParamBase
{
public void DoAction()
{
}
}
public class MyActionParamBase
{
public MyActionParamBase()
{
}
}
public sealed class MergeActionParam : MyActionParamBase
{
}
public class DefaultMyActionFactory : IMyActionFactory
{
public AbstractAction<T> CreateAction<T>(MyActionParamBase paramBase = null) where T : MyActionParamBase
{
return null;
}
}
public class MergeTest
{
private readonly IMyActionFactory _actionFactory = new DefaultMyActionFactory();
public void MergeWorks(/*params here*/)
{
var param = new MergeActionParam();
// populate param here
var sut = _actionFactory.CreateAction<MergeActionParam>(param);
sut.DoAction();
}
}
Scenario
Application has multiple parts.
Each part is in separate dll and implements interface IFoo
All such dlls are present in same directory (plugins)
The application can instantiate multiple instances of each part
Below is the code snippet for the interfaces, part(export) and the import. The problem I am running into is, the "factories" object is initialized with empty list.
However, if I try container.Resolve(typeof(IEnumerable< IFoo >)) I do get object with the part. But that doesn't serve my purpose (point 4). Can anyone point what I am doing wrong here?
public interface IFoo
{
string Name { get; }
}
public interface IFooMeta
{
string CompType { get; }
}
Implementation of IFoo in separate Dll
[ExportMetadata("CompType", "Foo1")]
[Export(typeof(IFoo)), PartCreationPolicy(CreationPolicy.NonShared)]
public class Foo1 : IFoo
{
public string Name
{
get { return this.GetType().ToString(); }
}
}
Main application that loads all the parts and instantiate them as needed
class PartsManager
{
[ImportMany]
private IEnumerable<ExportFactory<IFoo, IFooMeta>> factories;
public PartsManager()
{
IContainer container = ConstructContainer();
factories = (IEnumerable<ExportFactory<IFoo, IFooMeta>>)
container.Resolve(typeof(IEnumerable<ExportFactory<IFoo, IFooMeta>>));
}
private static IContainer ConstructContainer()
{
var catalog = new DirectoryCatalog(#"C:\plugins\");
var builder = new ContainerBuilder();
builder.RegisterComposablePartCatalog(catalog);
return builder.Build();
}
public IFoo GetPart(string compType)
{
var matchingFactory = factories.FirstOrDefault(
x => x.Metadata.CompType == compType);
if (factories == null)
{
return null;
}
else
{
IFoo foo = matchingFactory.CreateExport().Value;
return foo;
}
}
}
It seems to be an issue with ContainerBuilder. I tried alternate approach with CompositionContainer and it worked without hurdles. Pasting the code snippet for modified methods.
public PartsManager()
{
ConstructContainer();
}
private void ConstructContainer()
{
var catalog = new DirectoryCatalog(#"C:\plugins\");
var container = new CompositionContainer(catalog);
container.ComposeParts(this);
container.SatisfyImportsOnce(this);
}
It appears that it's a known issue in Autofac, that is currently closed with "won't fix" resolution.
If you remove dependency from Autofac like below it will work:
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition.Hosting;
using System.Linq;
using System.ComponentModel.Composition;
using System.Reflection;
namespace SO24132313
{
public interface IFoo
{
string Name { get; }
}
public interface IFooMeta
{
string CompType { get; }
}
[ExportMetadata("CompType", "Foo1")]
[Export(typeof(IFoo)), PartCreationPolicy(CreationPolicy.NonShared)]
public class Foo1 : IFoo
{
public string Name
{
get { return GetType().ToString(); }
}
}
class PartsManager
{
[ImportMany]
private IEnumerable<ExportFactory<IFoo, IFooMeta>> factories;
public PartsManager()
{
ConstructContainer(this);
}
private static void ConstructContainer(PartsManager p)
{
var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
var c = new CompositionContainer(catalog);
c.ComposeParts(p);
}
public IFoo GetPart(string compType)
{
var matchingFactory = factories.FirstOrDefault(
x => x.Metadata.CompType == compType);
if (factories == null)
{
return null;
}
else
{
IFoo foo = matchingFactory.CreateExport().Value;
return foo;
}
}
}
class Program
{
static void Main(string[] args)
{
PartsManager a = new PartsManager();
IFoo bla = a.GetPart("Foo1");
Console.WriteLine(bla);
}
}
}
I am trying to use the method of binding located here but having no luck
https://github.com/ninject/ninject.extensions.factory/wiki/Factory-interface
https://github.com/ninject/ninject.extensions.factory/wiki/Factory-interface%3A-Referencing-Named-Bindings
Keep in mind I am not trying to do it this way:https://gist.github.com/akimboyko/4593576
Rather I am trying to use the convention GetMercedes() to mean
I am basically trying to achieve this:https://gist.github.com/akimboyko/4593576 with conventions specified in the above examples.
using Ninject;
using Ninject.Extensions.Factory;
using Ninject.Modules;
using Ninject.Parameters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace Test.NinjectFactory
{
public class Program
{
public static void Main()
{
using (var kernel = new StandardKernel(new CarModule()))
{
var factory = kernel.Get<ICarFactory>();
var mercedes =factory.GetMercedes();
int i = 1;
}
}
public interface ICar
{
void Drive();
}
public class Mercedes : ICar
{
readonly ICarFactory carFactory;
public Mercedes(ICarFactory carFactory)
{
this.carFactory = carFactory;
}
public void Drive()
{
var Mercedes = this.carFactory.GetMercedes();
}
}
public interface ICarFactory
{
ICar GetMercedes();
}
public class CarModule : NinjectModule
{
public override void Load()
{
//https://github.com/ninject/ninject.extensions.factory/wiki/Factory-interface%3A-Referencing-Named-Bindings
Kernel.Bind<ICarFactory>().ToFactory();
Bind<ICar>().To<Mercedes>().NamedLikeFactoryMethod<ICarFactory>(x => x.GetMercedes());//doesnt work for me
}
}
}
}
I'm posting this as an answer because it is most likely the cause.
The factory extensions use prefixed Get methods as a standard. You'll run into issues by calling any of your factory methods with prefixed Get and using NamedLikeFactoryMethod. For example, GetFord, GetMercedes, GetNissan. You'll notice that, in the example at the link you provided, the function is called CreateMercedes.
Change your function name to CreateMercedes or anything that doesn't start with Get and it should be fine.
I found the anwswer here:
https://gist.github.com/akimboyko/5338320
It seems you need a function to take care of the binding
public class BaseTypeBindingGenerator<InterfaceType> : IBindingGenerator
{
public IEnumerable<IBindingWhenInNamedWithOrOnSyntax<object>> CreateBindings(Type type, IBindingRoot bindingRoot)
{
if (type != null && !type.IsAbstract && type.IsClass && typeof(InterfaceType).IsAssignableFrom(type))
{
string.Format("Binds '{0}' to '{1}' as '{2}", type, type.Name, typeof(InterfaceType)).Dump();
yield return bindingRoot.Bind(typeof(InterfaceType))
.To(type)
.Named(type.Name) as IBindingWhenInNamedWithOrOnSyntax<object>;
}
}
}