I have 2 classes, one derived from the other:
class Animal
{
public Animal AnimalMethod()
{
// do something
return this;
}
}
class Dog : Animal
{
public Dog DogMethod()
{
// do something
return this;
}
}
var dog = new Dog();
dog.DogMethod().AnimalMethod(); // 1 - this works
dog.AnimalMethod().DogMethod(); // 2 - this doesn't
How can I change my declaration(s) to be able to call the methods in the order "2" above in order to achieve a more fluent api?
Method chaining is a technique that is used for making multiple method calls on the same object, using the object reference just once. Example − Assume we have a class Foo that has two methods, bar and baz.
Explain Python class method chaining 1 Method Chaining. Method chaining is a technique that is used for making multiple method calls on the same object, using the object reference just once. 2 Example. Simple method chaining can be implemented easily in Python. 3 Output
If both base and derived classes are caught as exceptions, then the catch block of the derived class must appear before the base class. If we put the base class first then the derived class catch block will never be reached. For example, the following C++ code prints “Caught Base Exception“
A derived class is a class which takes some properties from its base class. It is true that a pointer of one class can point to other class, but classes must be a base and derived class, then it is possible. To access the variable of the base class, base class pointer will be used.
Use generic extension methods
Fluent/chaining methods work best as generic extension methods. A generic extension method knows the type of the instance variable and can return it as the same type that was passed in.
class Animal
{
public string CommonProperty { get; set; }
}
class Dog : Animal
{
public string DogOnlyProperty { get; set; }
}
static class ExtensionMethods
{
static public T AnimalMethod<T>(this T o) where T : Animal
{
o.CommonProperty = "foo";
return o;
}
static public T DogMethod<T>(this T o) where T : Dog
{
o.DogOnlyProperty = "bar";
return o;
}
}
class Example
{
static public void Test()
{
var dog = new Dog();
dog.DogMethod().AnimalMethod(); // 1 - this works
dog.AnimalMethod().DogMethod(); // 2 - this works now
Console.WriteLine("CommonProperty = {0}", dog.CommonProperty);
Console.WriteLine("DogOnlyProperty = {0}", dog.DogOnlyProperty);
var animal = new Animal();
animal.AnimalMethod();
//animal.DogMethod(); //Does not compile
//animal.AnimalMethod().DogMethod(); //Does not compile
}
}
Output:
CommonProperty = foo
DogOnlyProperty = bar
A workaround if you need private/protected access
One disadvantage of extension methods is that they cannot access private or protected members. Your instance method could. This hasn't been a problem for me (and it seems it's not an issue for the entire LINQ library either, which are written as extension methods). But there is a workaround if you need access.
You will need to implement the "chaining" method twice-- once as an interface method on the instance and a simple wrapper (one line of code) as an extension method that simply calls the first method. We use an interface method on the instance so that the compiler won't try to pick the instance method over the extension method.
interface IPrivateAnimal
{
Animal AnimalMethod();
}
interface IPrivateDog
{
Dog DogMethod();
}
class Animal : IPrivateAnimal
{
protected virtual string CommonProperty { get; set; } //notice this is nonpublic now
Animal IPrivateAnimal.AnimalMethod() //Won't show up in intellisense, as intended
{
this.CommonProperty = "plugh";
return this;
}
}
class Dog : Animal, IPrivateDog
{
private string DogOnlyProperty { get; set; } //notice this is nonpublic now
Dog IPrivateDog.DogMethod() //Won't show up in intellisense
{
this.DogOnlyProperty = "xyzzy";
return this;
}
}
static class ExtensionMethods
{
static public T AnimalMethod<T>(this T o) where T : class, IPrivateAnimal
{
return o.AnimalMethod() as T; //Just pass control to our hidden instance method
}
static public T DogMethod<T>(this T o) where T : class, IPrivateDog
{
return o.DogMethod() as T; //Just pass control to the instance method
}
}
class Example
{
static public void Test()
{
var dog = new Dog();
dog.DogMethod().AnimalMethod();
dog.AnimalMethod().DogMethod();
Console.WriteLine("CommonProperty = {0}", typeof(Dog).GetProperty("CommonProperty", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(dog));
Console.WriteLine("DogOnlyProperty = {0}", typeof(Dog).GetProperty("DogOnlyProperty", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(dog));
}
}
Output:
CommonProperty = plugh
DogOnlyProperty = xyzzy
There is one trick you could use to do this; though I'm not sure I would recommend it. Make Animal
generic and all your fluent methods return the type parameter:
class Animal<T> where T : Animal<T>
{
public T AnimalMethod() { return (T)this; }
}
Now your Dog inherits from the Dog form of animal
class Dog : Animal<Dog>
{
public Dog DogMethod() { return this; }
}
Now since the initial method will return a Dog
, you can call DogMethod
on it. This will be very hard to read; but it would accomplish your goal.
I did test this in C# interactive and it appears to work.
Apparently this is called the "Curiously Recurring" Pattern among other things. https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With