使用通用扩展方法
Fluent/chaining 方法最适合作为通用扩展方法。泛型扩展方法知道实例变量的类型,并且可以将其作为传入的相同类型返回。
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
DogOnlyProperty = 栏
如果您需要私人/受保护的访问权限的解决方法
扩展方法的一个缺点是它们不能访问私有或受保护的成员。您的实例方法可以。这对我来说不是问题(而且似乎整个 LINQ 库也不是问题,它们是作为扩展方法编写的)。但是,如果您需要访问权限,有一种解决方法。
您将需要实现两次“链接”方法——一次作为实例上的接口方法和一个简单的包装器(一行代码)作为简单调用第一个方法的扩展方法。我们在实例上使用接口方法,这样编译器就不会尝试选择实例方法而不是扩展方法。
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 = 插件
DogOnlyProperty = xyzzy