基类和派生类中的链接方法 [英] chaining methods in base and derived class
问题描述
我有2个班级,一个班级是从另一个班级派生的:
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
如何更改我的声明,以便能够以上面的"2"顺序调用方法,以实现更流畅的api?
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?
推荐答案
使用通用扩展方法
流利/链接方法最适合作为通用扩展方法.通用扩展方法知道实例变量的类型,并可以将其返回的类型与返回的类型相同.
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
}
}
输出:
CommonProperty = foo
CommonProperty = foo
DogOnlyProperty =条形
DogOnlyProperty = bar
需要私密/受保护的访问权限的解决方法
扩展方法的一个缺点是它们无法访问私有或受保护的成员.您的实例方法可以.这对我来说不是问题(似乎对于整个LINQ库也不是问题,整个LINQ库都是作为扩展方法编写的).但是,如果需要访问,则有一种解决方法.
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));
}
}
输出:
CommonProperty =插件
CommonProperty = plugh
DogOnlyProperty = xyzzy
DogOnlyProperty = xyzzy
这篇关于基类和派生类中的链接方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!