且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

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

更新时间:2022-03-22 16:51:42

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

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.