[英]C# - using extension methods to provide default interface implementation
我剛學習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#不支持多繼承,而我的類繼承了另一個類的行為。
我通常會推薦一個基類,但如果沒有,你可以這樣做:
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
另一種選擇可能是在需要新功能時創建一個包裝器來擴展基類:
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<T> 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 ""; } }
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.