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.
Related
I am trying to dynamically instantiate classes descendant of an abstract class, but the activator is forcing me to override the constructor to every descendant. Is there a way to avoid this?
P.S: I need to pass the parameters in the constructor, only there it can be Write, otherwise, it will always be read!
Is there a way to avoid this?
Short answer: Yes, when you define no constructor in your derived class, the (abstract) base class constructors are used. When you define one, you have to redefine all constructors.
Not without a workaround pattern.
EDIT: Sorry, I'm wrong that does only work for parameterless constructors.
How you can achive your goal,
is using a protected parameterless constructor and a static Create method:
public abstract class Duck {
private string _DucksParam0;
public string DucksParam0 {
get {
return _DucksParam0;
}
}
// Using protected, this constructor can only be used within the class instance
// or a within a derived class, also in static methods
protected Duck() { }
public static DuckT Create<DuckT>(string param0)
where DuckT : Duck
{
// Use the (implicit) parameterless constructor
DuckT theDuck = (DuckT)Activator.CreateInstance(typeof(DuckT));
// This is now your "real" constructor
theDuck._DucksParam0 = param0;
return theDuck;
}
}
public class Donald : Duck {
}
Usage (dotnetfiddle):
public class Program
{
public void Main()
{
Duck d = Duck.Create<Donald>("Hello World");
Console.WriteLine(d.DucksParam0);
}
}
Constructors are not inherited, so if you must instantiate a child object through a constructor with those parameters, then you need to write a new constructor in the child class that basically does base(p1, p2, ..., pn).
Looking at your code, seems that your constructors only assign/initialize fields, so there is no reason why you can't do that somewhere outside the constructor, as long as you control it appropriately. This might be a long shot, but I feel this is more what you want:
public abstract class Parent
{
protected bool foo
{
get;
private set; // just set the property setter as private
}
protected Parent() {
// protected so all instances are created through createAnotherX
// note that nothing is initialized here!
}
public abstract int Enter(); // To override in child classes
// Option 1: use generics
public static T createAnother1<T>(bool f) where T : Parent, new()
{
T p = new T();
p.foo = f;
return p;
}
// Option 2: use the runtime type
public static Parent createAnother2(Type t, bool f)
{
Parent p = Activator.CreateInstance(t) as Parent;
p.foo = f;
return p;
}
// Examples
public static void Main()
{
Parent p1 = Parent.createAnother1<Child>(true);
Parent p2 = Parent.createAnother2(typeof(Child), true);
}
}
// the child class only has to worry about overriding Enter()
public class Child : Parent
{
public override int Enter()
{
return 1;
}
}
Note that you must instantiate objects through the createAnotherX because the default constructor is protected. In addition, as per your comment, see that the property is defined so that only you can set values, which is what you tried to do in your code when explicitly ignoring the setter.
I have error
Cannot access a non-static member of outer type 'Project.Neuro' via
nested type 'Project.Neuro.Net'
with code like this (simplified):
class Neuro
{
public class Net
{
public void SomeMethod()
{
int x = OtherMethod(); // error is here
}
}
public int OtherMethod() // its outside Neuro.Net class
{
return 123;
}
}
I can move problematic method to Neuro.Net class, but I need this method outside.
Im kind of objective programming newbie.
Thanks in advance.
The problem is that nested classes are not derived classes, so the methods in the outer class are not inherited.
Some options are
Make the method static:
class Neuro
{
public class Net
{
public void SomeMethod()
{
int x = Neuro.OtherMethod();
}
}
public static int OtherMethod()
{
return 123;
}
}
Use inheritance instead of nesting classes:
public class Neuro // Neuro has to be public in order to have a public class inherit from it.
{
public static int OtherMethod()
{
return 123;
}
}
public class Net : Neuro
{
public void SomeMethod()
{
int x = OtherMethod();
}
}
Create an instance of Neuro:
class Neuro
{
public class Net
{
public void SomeMethod()
{
Neuro n = new Neuro();
int x = n.OtherMethod();
}
}
public int OtherMethod()
{
return 123;
}
}
you need to instantiate an object of type Neuro somewhere in your code and call OtherMethod on it, since OtherMethod is not a static method. Whether you create this object inside of SomeMethod, or pass it as an argument to it is up to you. Something like:
// somewhere in the code
var neuroObject = new Neuro();
// inside SomeMethod()
int x = neuroObject.OtherMethod();
alternatively, you can make OtherMethod static, which will allow you to call it from SomeMethod as you currently are.
Even though class is nested within another class, it is still not obvious which instance of outer class talks to which instance of inner class. I could create an instance of inner class and pass it to the another instance of outer class.
Therefore, you need specific instance to call this OtherMethod().
You can pass the instance on creation:
class Neuro
{
public class Net
{
private Neuro _parent;
public Net(Neuro parent)
{
_parent = parent;
}
public void SomeMethod()
{
_parent.OtherMethod();
}
}
public int OtherMethod()
{
return 123;
}
}
I think making an instance of outer class in inner class is not a good option because you may executing business logic on outer class constructor. Making static methods or properties is better option. If you insist making an instance of outer class than you should add another parameter to outer class contructor that not to execute business logic.
Why is the following C# not legal? Does there exist a proper workaround?
public class Base
{
public Base(Func<double> func) { }
}
public class Derived : Base
{
public Derived() : base(() => Method()) <-- compiler: Cannot access non-static method 'Method' in static context
{
}
public double Method() { return 1.0; }
}
It's effectively referring to "this" within the arguments to the base constructor, which you can't do.
If your delegate really doesn't need access to this (which your sample doesn't) you can just make it static. You could also use a method group conversion to make it simpler:
public class Base
{
public Base(Func<double> func)
{
double result = func();
}
}
public class Derived : Base
{
public Derived() : base(Method)
{
}
public static double Method() { return 1.0; }
}
If you do need to use "this", you could:
Make it a virtual method instead of calling a delegate
Make it a static method which takes an appropriate instance, e.g.
public class Base
{
public Base(Func<Base, double> func)
{
double result = func(this);
}
}
public class Derived : Base
{
public Derived() : base(x => Method(x))
{
}
private static double Method(Base b)
{
// The documentation would state that the method would only be called
// from Base using "this" as the first argument
Derived d = (Derived) b;
}
}
Basically you get the compiler error because you are referencing the instance-method Method without an instance of your class Derived. When calling base, the constructor has not yet finished and you don't have an instance of your class yet. If you made Method static it would work just fine.
Another solution to this is simply to defer the initialization of the delegate to the derived class:
public class Base {
protected Func<double> DoubleFunc { get; set; }
protected Base() {
// defer initialization by not setting DoubleFunc
// or another possibility is to set it to a dummy function:
DoubleFunc = () => 0;
}
public Base(Func<double> func) {
DoubleFunc = func;
}
}
public class Derived : Base {
public Derived() {
DoubleFunc = Method;
}
public double Method() { return 1.0; }
}
Have you tried making Method() static as the compiler indicates? The problem is that an instance of Derived isn't available until after the constructor has returned so you can't call an instance method on it.
The "workaround" would be to make Method() a static method.
I can't explain the technical reasons why this does not work but essentially you're trying to call a method on an instance which does not yet exist. How could it possibly work?
A co-worker of mine asked me last week if it were possible in C# to extend a generic class from its generic parameter. He said it was possible in C++.
What he wanted makes actually sense. He wanted a generic decorator to annotate an arbitrary class with additional information. Something like:
public class Decorator<T> : T
{
public object AdditionalInformation {get:set;}
}
So that he can now use this generic decorator everywhere instead of T.
The most similar thing I could come with was a container class with the original object, the additional information and an implicit conversion.
public class Decorator<T>
{
private readonly T _instance;
public Decorator(T instance)
{
_instance = instance;
}
public T Instance
{
get { return _instance; }
}
public object AdditionalInformation { get; set; }
public static implicit operator T(Decorator<T> deco)
{
return deco._instance;
}
}
But this is not the same because the implicit conversion is only one way. He cannot use it, for example, as a return type of a method because the additional information would be lost after he implicit conversion.
Does anybody have a better idea?
If you can derive all decorable classes from some base class, then you can try to store decorators in that base class and make its info recoverable. Here is sample code that is guaranteed to contain some errors, but you can get the idea.
public class Decorable
{
Dictionary<Type,object> decors = new Dictionary<Type,object>();
public void AddDecorator<D>(D decor) { decors[typeof(D)] = decor; }
public D GetDecorator<D>()
{
object value;
if (decors.TryGetValue(typeof(D), out value))
return (D)value;
else
return default(D);
}
}
public class Decorator<T> where T: class, Decorable
{
private readonly T _instance;
public Decorator(T instance)
{
_instance = instance;
instance.AddDecorator(this);
}
public T Instance
{
get { return _instance; }
}
public object AdditionalInformation { get; set; }
}
// use it like this
Decorator<MyClass> myDecor = myObj.GetDecorator<Decorator<MyClass>>();
If you cannot derive, then you must store info in some static class. But, as wcoenen commented, you would need to clear that info or you'd get memory leaks. Clearing is error prone and not always possible, so it's better to go with the first approach. For example (not thread safe, you must add locking if you plan to use it in multithreaded apps):
static public class Decorators
{
static Dictionary<object,Dictionary<Type,object>> instance = new Dictionary<object,Dictionary<Type,object>>();
public static void AddDecorator<T,D>(this T obj, D decor)
{
Dictionary<Type,object> d;
if (!instance.TryGetValue(obj, out d))
{
d = new Dictionary<Type,object>();
instance.Add(obj, d);
}
d[typeof(D)]=decor;
}
public static D GetDecorator<T,D>(this T obj)
{
// here must be double TryGetValue, but I leave it to you to add it
return (D) instance[obj][typeof(D)];
}
public static T ClearDecorators(this T obj) { instance.remove(obj); }
}
// Decorator<T> code stays the same, but without type constraint
public class BaseFoo
{
private string param;
public BaseFoo(string param)
{
this.param = param;
}
}
public sealed class SingletonFoo : BaseFoo
{
static readonly SingletonFoo instance = new SingletonFoo();
static SingletonFoo()
{
}
public static SingletonFoo Instance
{
get
{
return instance;
}
}
}
Is this kind of inheritance possible, where the base class requires a constructor with parameters? (The above code won't obviously compile because no parameter is passed to the base class.)
If yes, how is it accomplished?
You need to make an instance constructor, and then refer to it:
public sealed class SingletonFoo : BaseFoo
{
static readonly SingletonFoo instance = new SingletonFoo("Some Value");
static SingletonFoo()
{
}
private SingletonFoo(string value) : base(value)
{
}
// ...
This will let you declare the parameter in the inline constructor, and call it down the chain.
You use the 'base' keyword:
public SingletonFoo (string param) : base(param)
{
}
I'm pretty sure a 'singleton' deriving from a non-singleton base class completely invalidates the entire concept of the pattern, which is often used inappropriately to start with.
Static constructors do not take parameters, so the only way to pass them to the base class would be via constructor-chaining but I'm pretty sure you can't invoke an instance constructor from a static constructor...
What exactly are you trying to do here?