C# - 使用扩展方法提供默认接口的实现 [英] C# - using extension methods to provide default interface implementation

查看:179
本文介绍了C# - 使用扩展方法提供默认接口的实现的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我只是学习C#的扩展方法,并想知道如果我可以用它来提供一个接口的默认实现

I'm just learning about C# extension methods, and was wondering if I can use it to provide a default implementation for an interface.

说:

public interface Animal {
    string MakeSound();
}

public static string MakeSound(this Animal) {
    return "";
}



然后

Then

public class Dog : Animal {
    string MakeSound() {
        return "Bark";
    }
}

public class Porcupine : Animal {
}

和最后的:

Animal dog = new Dog();
Animal porcupine = new Porcupine();

Print(dog.MakeSound());
Print(porcupine.MakeSound());



我想豪猪和没有明确实施的任何其他动物 MakeSound 来使用返回一个空字符串默认扩展方法,但狗,确实有一个明确的实施返回自己的实现,如汪汪任何动物。

I'd like the porcupine and any other animals that have not explicitly implemented MakeSound to use the default extension method that returns an empty string, but dog and any animal that does have an explicit implementation return its own implementation such as "Bark".

所以我的问题:
1,这是可行的?
2.如果没有,有没有实现一个接口的默认行为的任何其他方式?

So my questions: 1. Is this doable? 2. If not, is there any other way to implement default behavior for an interface?

抽象类,而不是接口不是一种选择,因为C#没有按'科技支撑多重继承我的类继承另一个类的行为。

Abstract class instead of interface is not an option because C# doesn't support multiple inheritance and my classes are inheriting behavior of another class.

推荐答案

我一般推荐一个基类,但是,如果那是了,你可以做这样的事情:

I'd generally recommend a base class, however, if that's out, you can do something like this:

public interface IAnimal { }

public interface INoisyAnimal : IAnimal {
    string MakeSound();
}

public static class AnimalExtensions { 
    public static string MakeSound(this IAnimal someAnimal) {
        if (someAnimal is INoisyAnimal) {
            return (someAnimal as INoisyAnimal).MakeSound();
        }
        else {
            return "Unknown Noise";
        }
    }
}

public class Dog : INoisyAnimal {
    public string MakeSound() {
        return "Bark";
    }
}

public class Porcupine : IAnimal { }

这使得每个 IAnimal 的像 INoisyAnimal 即使它不是'吨真的之一。例如:

This makes every IAnimal look like a INoisyAnimal even if it isn't really one. For example:

IAnimal dog = new Dog();
IAnimal porcupine = new Porcupine();

Console.WriteLine(dog.MakeSound());            // bark
Console.WriteLine(porcupine.MakeSound());      // Unknown Noise



不过,这还不是一个实际的接口的实现。请注意,尽管表面上看起来

However, this still isn't an actual implementation of the interface. Notice that despite appearances

Console.WriteLine(porcupine is INoisyAnimal);  // false






另一种选择可能是创建一个需要新的功能时,包装来扩展你的基类:


Another option might be to create a wrapper to extend your base class when new functionality is needed:

public class NoisyAnimalWrapper : INoisyAnimal {
    private readonly IAnimal animal;
    public NoisyAnimalWrapper(IAnimal animal) {
        this.animal = animal;
    }

    public string MakeSound() {
        return "Unknown Noise";
    }
}

public static class AnimalExtensions { 
    public static INoisyAnimal Noisy(this IAnimal someAnimal) {
        return someAnimal as INoisyAnimal ?? 
                new NoisyAnimalWrapper(someAnimal);
    }
}



然后,你可以创建一个 INoisyAnimal 任何 IAnimal 每当你需要:

INoisyAnimal dog = new Dog();
INoisyAnimal porcupine = new Porcupine().Noisy();

Console.WriteLine(dog.MakeSound());            // bark
Console.WriteLine(porcupine.MakeSound());      // Unknown Noise

您也可以使包装通用(如 NoisyAnimal< T>其中T:IAnimal,新的),并获得完全摆脱扩展方法。根据实际使用情况下,这可能是优选的到先前的选项。

You could also make the wrapper generic (e.g. NoisyAnimal<T> where T : IAnimal, new) and get rid of the extension method altogether. Depending on your actual use case, this may be preferable to the previous option.

这篇关于C# - 使用扩展方法提供默认接口的实现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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