Reputation: 363
Let say we have Class A and Class B. ClassB extends Class A. (ClassB : ClassA)
Now let's say that whenever I instantiate ClassB, I'd like to Run some Random code and only then call "base" to reach ClassA constructor.
Like:
class ClassA
{
public ClassA()
{
Console.WriteLine("Initialization");
}
}
class ClassB : ClassA
{
public ClassB() //: base()
{
// Using :base() as commented above, I would execute ClassA ctor before // Console.WriteLine as it is below this line...
Console.WriteLine("Before new");
//base() //Calls ClassA constructor using inheritance
//Run some more Codes here...
}
}
In the programming language I usually work with, I can do that, by simply calling super()
after Console.WriteLine()
; But I cant make it in C#. Is there any other syntax or other way to do that?
Upvotes: 26
Views: 21264
Reputation: 1381
I am surprised noone has suggested using an abstract method - though it does rely on the base being implemented as an abstract class which wont work for all cases (although you could simply fork the inheritance and stack the non-abstract on top if yu have to). This has the advantage of ensuring the integrity of your code without resorting to hackiness. Because we are using abstract, it is not possible to instantiate the derived class without declaring initCode.
using System;
abstract class ClassA
{
internal abstract initCode();
public ClassA()
{
initCode();
Console.WriteLine("Initialization");
}
}
class ClassB : ClassA
{
public ClassB()
{
}
internal override initCode()
{
Console.WriteLine("Before new");
return 0; // We really don't care
}
}
//If you need to effectively get the non-abstract of ClassA
class ClassC : ClassA
{
public ClassB()
{
}
internal override initCode()
{
}
}
Upvotes: 1
Reputation: 511
Actually, you can:
class Foo
{
public Foo(string s)
{
Console.WriteLine("inside foo");
Console.WriteLine("foo" + s);
}
}
class Bar : Foo
{
public Bar(string s) : base(((Func<string>)(delegate ()
{
Console.WriteLine("before foo");
return "bar" + s;
}))())
{
Console.WriteLine("inside bar");
}
}
class Program
{
static void Main(string[] args)
{
new Bar("baz");
}
}
Output:
before foo
inside foo
foobarbaz
inside bar
But I will prefer to not use this trick if it is possible.
Upvotes: 8
Reputation: 1
I had the same problem. I found this solution to be the best if you don't have access to the base class.
public class BaseClass
{
public BaseClass(string someValue)
{
Console.WriteLine(someValue);
}
}
public class MyClass : BaseClass
{
private MyClass(string someValue)
: base(someValue)
{
}
public static MyClass GetNewInstance(string someValue, bool overrideValue = false)
{
if (overrideValue)
{
someValue = "42";
}
return new MyClass(someValue);
}
}
Upvotes: 0
Reputation: 87
Another elegant solution would be to completely rethink how your objects are constructed. In the constructor of your base class you can call your own construct
function, and you omit dependent future constructors, in the following way:
public class ClassA
{
public ClassA()
{
Construct();
}
public virtual void Construct()
{
Console.WriteLine("3");
}
}
public class ClassB : ClassA
{
public override void Construct()
{
Console.WriteLine("2");
base.Construct();
}
}
public class ClassC : ClassB
{
public override void Construct()
{
Console.WriteLine("1");
base.Construct();
}
}
Upvotes: 7
Reputation: 5357
Recently I ran into a scenario where I needed to calculate some logic before passing the result into base.
I could just do something like
public SomeConstructor: base(FlagValue == FlagValues.One || FlagValues.Two ? "OptionA" : "OptionB")
{
}
But I find that to be ugly, and can get really long horizontally. So I opted instead to use Func Anonymous methods.
E.g. imagine you have a base class,
public class SomeBaseClass
{
public SomeBaseClass(Func<string> GetSqlQueryText){
string sqlQueryText = GetSqlQueryText();
//Initialize(sqlQueryText);
}
}
Now you inherit from that and want to do some logic to determine the sql query text,
public class SomeSqlObject : SomeBaseClass
{
public SomeSqlObject(ArchiveTypeValues archiveType)
: base(delegate()
{
switch (archiveType)
{
case ArchiveTypeValues.CurrentIssues:
case ArchiveTypeValues.Archived:
return Queries.ProductQueries.ProductQueryActive;
case ArchiveTypeValues.AllIssues:
return string.Format(Queries.ProductQueries.ProductQueryActiveOther, (int)archiveType);
default:
throw new InvalidOperationException("Unknown archiveType");
};
})
{
//Derived Constructor code here!
}
}
In this way you can execute code before Base is called and (in my opinion) it's not really hacky.
Upvotes: 0
Reputation: 1325
Another hack if you can get away with calling a static method.
public class ClassA
{
public ClassA()
{
Debug.WriteLine("Call A Constructor");
}
}
public class ClassB:ClassA
{
public ClassB():this(aMethod())
{
}
private ClassB(object empty):base()
{
Debug.WriteLine("Class B Second Constructor");
}
private static object aMethod()
{
Debug.WriteLine("Run me First");
return null;
}
}
Upvotes: 8
Reputation: 1502096
There's a hacky way of doing it using an instance variable initializer:
using System;
class ClassA
{
public ClassA()
{
Console.WriteLine("Initialization");
}
}
class ClassB : ClassA
{
private readonly int ignoreMe = BeforeBaseConstructorCall();
public ClassB()
{
}
private static int BeforeBaseConstructorCall()
{
Console.WriteLine("Before new");
return 0; // We really don't care
}
}
class Test
{
static void Main()
{
new ClassB();
}
}
The less hacky way of doing it is to rethink how you construct a ClassB
to start with. Instead of having clients call the constructor directly, provide a static method for them to call:
public static ClassB CreateInstance()
{
Console.WriteLine("Before initialization stuff");
return new ClassB();
}
Upvotes: 33
Reputation: 2407
You can not call base constructor. But a different thing is that when you declare an object of derived class both constructor derived and base is called.
class ClassA
{
public ClassA()
{
Console.WriteLine("Initialization");
}
}
class ClassB : ClassA
{
public ClassB() //: base()
{
// Using :base() as commented above, I would execute ClassA ctor before // Console.WriteLine as it is below this line...
Console.WriteLine("Before new");
//base() //Calls ClassA constructor using inheritance
//Run some more Codes here...
}
}
void main(string[] args)
{
ClassB b = new ClassB();
}
Upvotes: 0
Reputation: 13097
You can't do that with C#. Your best bet is to extract that code into it's own method in the parent and then call that from the child when you're ready.
Upvotes: 1
Reputation: 12920
C# doesn't allow calling base constructors inside constructor bodies, different from Java.
Upvotes: 1