簡體   English   中英

C# - 使用擴展方法提供默認接口實現

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM