我可以限制传递给我的方法的类型,以便在编译而不是运行时捕获这种类型的错误吗?
我当前的代码如下:
void Main()
{
var dog = new Dog();
SaveAnimal(dog);
}
void SaveAnimal(Animal animal) {
var isAnimal = animal.GetType().UnderlyingSystemType == typeof(Animal);
Debug.Assert(isAnimal, "You can not save dogs!");
}
class Animal {
public int Legs { get; set; }
}
class Dog : Animal {
public int TailLength { get; set; }
}
答案 0 :(得分:6)
否,该语言无法静态地将其视为使用错误。
您可以在运行时声明它,因为您已经在执行它了。但是,这与继承的精神背道而驰,因为一个基本的假设是派生类型必须替换基类型(Liskov替换原理)。
也许您可以通过给Animal
一种新方法abstract void Save()
使动物自救。然后,每只动物决定做什么。 Dog
然后可以抛出NotSupportedException
。
答案 1 :(得分:2)
是的,但只能使用通用和接口来解决。
您需要做的是声明3个接口
public interface ISaveAbleBase { }
public interface ISaveAble : ISaveAbleBase{ }
public interface INotSaveAble : ISaveAbleBase { }
现在,您需要为Animal类提供一个通用参数,并将其约束为ISaveAbleBase
类型。
class Animal<T> where T: ISaveAbleBase
{
public int Legs { get; set; }
}
现在,您可以在派生类中指定是否可以保存它们的方式:
class Dog : Animal<INotSaveAble>
{
public int TailLength { get; set; }
}
然后您可以使方法通用,并将类型限制为只能保存的缩略语
void SaveAnimal<T>(T animal) where T: Animal<ISaveAble>
现在结果看起来如下:
void Main()
{
var dog = new Dog();
SaveAnimal(dog); // does not compile
Animal<ISaveAble> generalAnimal = new Animal<ISaveAble>();
SaveAnimal(generalAnimal); // compiles
}
免责声明:此构造还可以让您拥有无法保存的常规Animal
:
Animal<INotSaveAble> generalAnimalNotSave = new Animal<INotSaveAble>();
SaveAnimal(generalAnimalNotSave); // does not compile
PS。这个答案的灵感来自this post
答案 2 :(得分:1)
没有标准的方法,但是有一个简单的(和愚蠢的)解决方法。
using System.Diagnostics;
namespace Test
{
internal static class Program
{
private static void Main()
{
var dog = new Dog();
SaveAnimal(dog);
}
private static void SaveAnimal(Animal animal)
{
var isAnimal = animal.GetType().UnderlyingSystemType == typeof(Animal);
Debug.Assert(isAnimal, "You can not save dogs!");
}
private static void SaveAnimal(ICanNotSave animal)
{
Debug.Fail("Can not save");
}
}
internal class Animal
{
public int Legs
{
get; set;
}
}
internal interface ICanNotSave
{
}
internal sealed class Dog : Animal, ICanNotSave
{
public int TailLength
{
get; set;
}
}
}
当您有两个SaveAnimal
方法(其中一个用于Animal
,另一个用于接口)在所有无法保存的后代上实现时,编译器将报告CS0121错误。 / p>
以下方法或属性之间的调用不明确:“ Program.SaveAnimal(Animal)”和“ Program.SaveAnimal(ICanNotSave)”
请记住,当您使用SaveAnimal
方法时,仍然可以使用SaveAnimal((Animal)dog)