基类和派生类中的链接方法 [英] chaining methods in base and derived class

查看:66
本文介绍了基类和派生类中的链接方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆