C# – 使用扩展方法提供默认接口实现

我刚刚学习了C#扩展方法,并想知道我是否可以使用它来为接口提供默认实现。

说:

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

然后

 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动物使用返回空字符串的默认扩展方法,但是狗和任何具有显式实现的动物都会返回自己的实现,例如“Bark”。

所以我的问题:1。这可行吗? 2.如果没有,是否有其他方法可以实现接口的默认行为?

抽象类而不是接口不是一个选项,因为C#不支持多重inheritance,而我的类inheritance了另一个类的行为。

我通常会推荐一个基类,但如果没有,你可以这样做:

 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即使它不是真的。 例如:

 IAnimal dog = new Dog(); IAnimal porcupine = new Porcupine(); Console.WriteLine(dog.MakeSound()); // bark Console.WriteLine(porcupine.MakeSound()); // Unknown Noise 

但是,这仍然不是接口的实际实现。 请注意,尽管出现了

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

另一个选择可能是在需要新function时创建一个包装器来扩展基类:

 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); } } 

然后,您可以在需要时从任何IAnimal创建一个INoisyAnimal

 INoisyAnimal dog = new Dog(); INoisyAnimal porcupine = new Porcupine().Noisy(); Console.WriteLine(dog.MakeSound()); // bark Console.WriteLine(porcupine.MakeSound()); // Unknown Noise 

你也可以使包装器通用(例如NoisyAnimal where T : IAnimal, new )并完全摆脱扩展方法。 根据您的实际使用情况,这可能比以前的选项更可取。

我不确切地知道你的实际情况是什么,或者你只是在试验,但是,如果只有一些动物吵闹,那么它可能是Interface segregation一个好例子。

例如:

 public class Dog : IAnimal, INoisy { public string MakeSound() { return "Bark"; } } public class Porcupine : IAnimal { } 

然后,您将只调用MakeSound或实际上有噪声的对象。

这样的事怎么样? 它允许你避免使用基类,你可以做你想到的,对吧?

 public interface Animal { // Fields string voice { get; } } public static class AnimalHelper { // Called for any Animal public static string MakeSound(this Animal animal) { // Common code for all of them, value based on their voice return animal.voice; } } public class Dog : Animal { public string voice { get { return "Woof!"; } } } public class Purcupine : Animal { public string voice { get { return ""; } } }