Consider the following class
class Foo
{
public Foo(IBar bar=null)
{
}
}
I have a need to inject an alternate constructor to allow the IBar instance to be provided on demand rather than injected.
class Foo
{
public Foo(IBar bar=null)
{
}
public Foo(Func<IBar> barFunc) : this((IBar)null)
{
}
}
However there is a bunch of code in several dependent projects like:
Foo foo = new Foo(null);
This code won't compile anymore due to the ambiguous constructor reference.
Obviously I could change the code to
Foo foo = new Foo((IBar)null);
But this would require changes to a whole bunch of projects, and my goal is a transparent change. Is there some way to specify which constructor to call if ambiguous? Or a way to indicate to the compiler that barFunc cannot be null
At the moment, I am looking at this but it feels .... dirty
class Foo
{
public Foo(IBar bar=null)
{
}
public Foo(Func<IBar> barFunc, bool notUsed) : this((IBar)null)
{
}
}
Maybe use a static method ala named constructor idiom:
class Foo
{
...
public static Foo Create(Func<IBar> func)
{
return new Foo(func());
}
}
Make the Foo(Func<IBar>) constructor private, and add a factory method:
public static Foo WithIBarFunc(Func<IBar> func) {
return new Foo(func);
}
If you can, delete the the Foo(Func<IBar>) constructor all together and write the method like this:
public static Foo WithIBarFunc(Func<IBar> func) {
var foo = new Foo(null);
// initialise foo with func...
return foo;
}
Related
I have the following interfaces and concrete implementations:
interface IFoo {
string Name { get ;}
}
class Foo :IFoo{
public string Name { get; set; }
}
interface IBar {
string Name { get; }
}
class Bar : IBar {
public string Name { get;set;}
public Bar(Foo foo) {
}
}
You can see that Bar has a dependency on Foo in the class constructor.
These are my bindings:
kernel.Bind<IFoo>().ToConstant(new Foo() { Name="Foo"; });
kernel.Bind<IBar>().To<Bar>();
When I use kernel.Get and ask for Bar, there are no errors, but the Foo dependency is a different instance of Foo that I originally bound. I expected to see Foo with a name of "Foo" when I inspect the Foo instance inside of the Bar constructor, but instead I see Foo { Name = null }.
When I bind to concrete Foo, everything works as expected:
var foo = new Foo() { Name="Foo" };
kernel.Bind<IFoo>().ToConstant(foo);
kernel.Bind<Foo>().ToConstant(foo);
kernel.Bind<IBar>().To<Bar>();
var bar= kernel.Get<Bar>(); // works! foo has name "Foo"
Is there a convenient way to bind a specific instance of Foo to all the available interfaces, and concrete types?
For example:
class ConcreteFoo : AbstractFoo, IFoo {
...
}
var foo = new Foo();
kernel.Bind<IFoo>().ToConstant(foo);
kernel.Bind<AbstractFoo>().ToConstant(foo);
kernel.Bind<ConcreteFoo>().ToConstant(foo);
I have a generic framework. Outside of the framework is Foo and Bar that the clients define. I want clients to have the flexibility of specifying IFoo or Foo in the Bar constructor. If the constructor was defined as Bar(IFoo), the client might be casting it to Foo anyway.
There's no such functionality provided by ninject. What ninject offers is binding to multiple types, for example:
Bind<IFoo,Foo>().To<Foo>().InSingletonScope();
Ensures no matter what combination of IFoo and Foo are requested, you always get the same Foo instance.
Then, there's Ninject.Extensions.Conventions which can look for types (like all classes of an assembly) and bind them to all their interface, all their base types,... but only either or, not both. You could use this to achieve what you want, but it would require quite some code on your end, too,.. and it would be kind of akward.
So, in my opinion, it's best just to roll your own:
using Ninject.Infrastructure.Language;
public static void RegisterConstantAsAllTypes(IBindingRoot bindingRoot, object instance)
{
Type t = instance.GetType();
IEnumerable<Type> typesToBind = t.GetAllBaseTypes()
.Concat(t.GetInterfaces())
.Except(new[] { typeof(object) });
bindingRoot
.Bind(typesToBind.ToArray())
.ToConstant(instance);
}
Given your example the following test passes:
[Fact]
public void FactMethodName()
{
var kernel = new StandardKernel();
var foo = new Foo();
RegisterConstantAsAllTypes(kernel, foo);
kernel.Get<IFoo>().Should().Be(foo);
kernel.Get<Foo>().Should().Be(foo);
kernel.Get<AbstractFoo>().Should().Be(foo);
}
This is a copy of https://github.com/seesharper/LightInject/issues/173
I tried to automatically create concrete types using fallback and .Create() but it somehow loops itself and I don't understand why.
Here is my test code:
public class Foo
{
public Foo(IBar bar, IBar2 bar2)
{
}
}
public interface IBar2
{
}
class Bar2 : IBar2
{
}
public interface IBar
{
}
class Bar : IBar
{
}
private ServiceContainer container = new ServiceContainer();
container.RegisterFallback((t, s) => true, Factory);
container.Register<IBar, Bar>();
container.Register<IBar2, Bar2>();
var foo = container.GetInstance<Foo>(); // Error here
private object Factory(ServiceRequest req)
{
return container.Create(req.ServiceType);
}
Could you please advise?
It loops even if the Factory method looks like this:
private object Factory(ServiceRequest req)
{
container.Register(typeof(Foo));
return container.GetInstance<Foo>();
}
but works perfectly if I register Foo beforehand (which I obviously want to avoid)
container.Register(typeof(Foo));
var foo = container.GetInstance<Foo>(); //ok
I am the author of LightInject and the issue has been updated with a workaround that enables the container to resolve unregistered concrete classes.
https://github.com/seesharper/LightInject/issues/173
It's the bug that was confirmed in https://github.com/seesharper/LightInject/issues/173 and is looked after by author
If I have a class like this:
class myClass
{
string foo;
string bar;
public myClass(string foo, string bar)
{
//does some stuff here
(myClass)deserializer.Deserialize(reader); //assign the return value to the instance
}
}
Something that would achieve this:
public myClass(string foo, string bar)
{
//does some stuff here
myClass tempobject = (myClass)deserializer.Deserialize(reader); //this method has a return value of type myClass
this.foo = tempObject.foo;
this.bar = tempObject.bar;
}
SomeMethod returns a value of type myClass. Can I assign this returned value to the instance of myClass that invoked the constructor?
No, that isn't possible.
What you could do is make SomeMethod static and the constructor private. This is called the Factory Pattern, as you have a method used to create instances of your class. The factory pattern is often used to create instances of various different concrete classes at runtime.
As you've updated your question to say that the method isn't in your class, then i think the best option is to make a method in your class that takes another instance of the class, then in that method, copy all properties. You'd call that in your constructor.
No -- the constructor doesn't return an instance to the class you've created because the object has to be instantiated before the constructor gets called. The constructor just does initialization work on the class that was created moments ago.
Instead, you'll have to use a "factory" pattern, like this:
public class SomeClass {
public static SomeClass CreateNew(string foo, string bar) {
if (SOME_CONDITION) {
// use our SomeMethod
return SomeMethod(foo,bar);
} else {
// otherwise use the normal constructor
return new SomeClass(x,y);
}
}
}
// ... elsewhere...
SomeClass foo = Someclass.CreateNew("x","y");
class myClass
{
string foo;
string bar;
public myClass(string foo, string bar)
{
//does some stuff here
mYclass result = SomeMethod(foo,bar); //this method has a return value of type myClass
this.foo = result.foo;
this.bar = result.bar;
}
}
You can write a static method that allows you to create an object from your reader like this:
class myClass
{
public string foo { get; set; }
public string bar { get; set; }
public myClass()
{
//does some stuff here
}
public static myClass FromReader(Reader reader)
{
return (myClass)deserializer.Deserialize(reader);
}
}
and use it in your code like this:
myClass newMyClass = myClass.FromReader(reader);
I have a follwing class structure:
public abstract class AbstractFoo
{
public virtual void Prepare()
{
}
}
public class Foo : AbstractFoo
{
public override void Prepare()
{
}
}
public class Bar : Foo
{
public override void Prepare()
{
}
}
public class ClassThatUses
{
public Foo Foo;
}
var classThatUsesInstance = new ClassThatUses { Foo = new Bar (); }
Somehow in ClassThatUses i need to call (through the reflection - mandatory) Prepare method of the class Bar.
Instead of question (???) marks i need to make a reflection code that will call the Prepare method of Bar rather than foo.
Basically, it should be something like:
classThatUsesInstance.GetType.GetProperties()[0]
-> somehow understand that it's actually Bar, but not Foo.
-> call method (which i know how to do, i just need the RIGHT method to be used)
I don't know whether it's Bar, or BarBar, or BarBarBar. I need to find out the REAL type of assigned field rather then type it was casted to.
Is this any possible?
Or is it at least possible to find out the real type of the Foo field in runtime?
p.s. i realize that without reflection it will be called - no problem. this is more of a theory.
UPD: http://msdn.microsoft.com/en-us/library/a89hcwhh.aspx
Note that you cannot use the MethodInfo object from the base class to invoke the overridden method in the derived class, because late binding cannot resolve overrides.
Does that mean the problem is unsolvable?
The GetType method will give you the real type of Foo at runtime:
public class ClassThatUses
{
public Foo Foo { get; set; }
public void CallPrepare()
{
// Foo.Prepare();
Foo.GetType().GetMethod("Prepare").Invoke(Foo, null);
}
}
Following your edit, if you want to find the runtime type of Foo for a particular instance of ClassThatUses then you'll need to use GetValue to interrogate the value of Foo on that instance:
ClassThatUses o = new ClassThatUses() { Foo = new Bar() };
// Type fooType = o.Foo.GetType();
Type fooType = o.GetType().GetProperty("Foo").GetValue(o, null).GetType();
typeof(Bar).GetMethod("Prepare").Invoke(foo, new object[] { });
or
foo.GetType().GetMethod("Prepare").Invoke(foo, new object[] { });
is it at least possible to find out
the real type of the Foo field in
runtime?
Yes, with foo.GetType()
Why does the first constructor in ClassA cause the compiler error 'cannot use "this" in member intializer'?
... or how can i get this to work?
Thanks
public sealed class ClassA : IMethodA
{
private readonly IMethodA _methodA;
public ClassA():this(this)
{}
public ClassA(IMethodA methodA)
{
_methodA = methodA;
}
public void Run(int i)
{
_methodA.MethodA(i);
}
public void MethodA(int i)
{
Console.WriteLine(i.ToString());
}
}
public interface IMethodA
{
void MethodA(int i);
}
You are allowed to use the this(...) syntax to invoke another constructor at the same level - however, you cannot use this (the current instance) in this context.
The easiest option here is to duplicate the assignment code (_methodA = methodA).
Another option might be null-coalescing:
public ClassA():this(null)
{}
public ClassA(IMethodA methodA)
{ // defaults to "this" if null
_methodA = methodA ?? this;
}
This is called out in section 10.11.1 of the C# spec
An instance constructor initializer
cannot access the instance being
created. Therefore it is a
compile-time error to reference this
in an argument expression of the
constructor initializer, as is it a
compile-time error for an argument
expression to reference any instance
member through a simple-name.
There is no way to get this to work with an instance constructor because this cannot be accessed. What you could do is make the constructor private, create an initialization method and a static constructor.
public sealed class ClassA : IMethodA {
private ClassA() { }
private void Initialize(IMethodA param) { ... }
public static ClassA Create() {
var v1 = new ClassA();
v1.Initialize(v1);
return v1;
}
public static ClassA Create(IMethodA param) {
var v1 = new ClassA();
v1.Initialize(param);
return v1;
}
}
You're trying to pass the object before it is constructed. Although the compiler could do something sensible in this case, in general that won't work.
Your actual example works if you just do this:
public ClassA()
{
_methodA = this;
}
But you probably want to share more logic, so just use a function.
public ClassA()
{
SetStuff();
_methodA = this;
}
public ClassA(IMethodA methodA)
{
SetStuff();
_methodA = methodA;
}
You can't use the this keyword when chaining constructors essentially because this refers to an object that hasn't been instantiated yet (creation of the object doesn't begin until some (the top-level or base) constructor block has been entered). Moreover, why exactly would you want to do this? It seems rather pointless when you have access to the this keyword everywhere.
I recommend simply using independent constructors as such:
public sealed class ClassA : IMethodA
{
private readonly IMethodA _methodA;
public ClassA()
{
_methodA = this;
}
public ClassA(IMethodA methodA)
{
_methodA = methodA;
}
}
Perhaps I misunderstand what you're trying to do, but hopefully that will solve the issue for you.