Reputation: 4365
I have a library that creates and setups objects for me, then I can use those objects to do stuff.
Let's say I'm given object "a" of class "A"
So I want to override a method in that specific object, I don't want to change the code of its class because that would require changing the library.
In Ruby I can do that using Singleton Classes, like:
class FirstClass
def test
p "test"
end
end
o = FirstClass.new
class << o
def test
p "overridden"
end
def extraMethod
p "ok"
end
end
o.test # prints "overridden"
o.extraMethod
Now how can I do the same in C#?
Update
I ended up not using the answer I submitted because it's too ugly and it requires changing all private fields in the base class to either protect or public to make them exist in the derived class hence I can copy values from base to derived.
The way I ended up using is to pass a Type derived from the base class to the library and change the library so that it creates instances using:
(A)Activator.CreateInstance(mytype, arguments);
Upvotes: 3
Views: 3445
Reputation: 4365
There is an ugly way to do this actually.
I was thinking of using inheritance and downcasting, but downcasting is invalid. However, you can use reflection to achieve the same outcome.
static void Main()
{
A a = new A();
a.FieldA = 999; // change the object
a.test(); // "This is A and FieldA is 999"
//B b = (B)a; // => Error: Invalid you cannot downcast !
// using reflection we turn "a" into an instance of B that is a copy of the old "a"
a = new B(a);
a.test(); // This will call the method in B: "Calling the new method" "This is B and FieldA is 999 and FieldB is 10"
// a.newMethod(); => Error cannot access this method because "a" is declared as an instance of A (even though it's actually of B now)
B b = (B)a; // Now downcasting works fine (because A is an instance of B actually)
b.newMethod(); // works as expected: "This is B and FieldA is 999 and FieldB is 10"
}
class A
{
public int FieldA;
public A()
{
FieldA = 100;
}
virtual public void test()
{
Console.WriteLine("This is A and FieldA is {0}", FieldA);
}
}
class B : A
{
int FieldB;
public B(A a)
{
// copy all fields
foreach (FieldInfo pi in typeof(A).GetFields())
GetType().GetField(pi.Name).SetValue
(this, pi.GetValue(a));
// add this field:
FieldB = 10;
}
// We can override methods
override public void test()
{
Console.WriteLine("Calling the new method:");
newMethod();
}
// Add a new method but it will only be visible after casting A to B
public void newMethod()
{
Console.WriteLine("This is B, FieldA is {0} and FieldB is {1}", FieldA, FieldB);
}
}
So I have overridden the methods within "a" and added new fields to it.
I realise this doesn't achieve the same as what you can do in Ruby, but at least I can override methods and add methods/fields that can be used inside the methods I'm overriding.
Upvotes: 0
Reputation: 44038
To "override a method" in runtime (notice the quotes) is possible in C# by using Delegates
public class SomeClass
{
public SomeClass()
{
//set the default
OverridableMethod = () => MessageBox.Show("Default!");
}
public void StandardMethod()
{
//Call it.
OverridableMethod();
}
public Action OverridableMethod {get;set;}
}
usage:
var some1 = new SomeClass();
some1.StandardMethod(); //Shows "Default!"
some1.OverridableMethod(); //Shows "Default!"
var some2 = new SomeClass {OverridableMethod = () => MessageBox.Show("Override!!")};
some2.StandardMethod(); //Shows "Override!"
some2.OverridableMethod(); //Shows "Override!"
Upvotes: 1
Reputation: 564413
C# doesn't (directly) support runtime extension of types, other than via the dynamic
mechanisms.
The closest option would likely be to use ExpandoObject
with dynamic
:
dynamic o = new ExpandoObject();
o.a = 10;
o.ExtraMethod = new Action( () => Console.WriteLine("ok") );
// Invoke
o.ExtraMethod();
That being said, this is not a typical way to work with C#.
Upvotes: 4