代码之家  ›  专栏  ›  技术社区  ›  Espo

是否可以将传递给.NET方法的变量类型限制为非派生类?

  •  1
  • Espo  · 技术社区  · 6 年前

    我是否可以约束传递给方法的类型,使其在编译而不是运行时捕获这种类型的错误?

    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; }
    }
    
    3 回复  |  直到 6 年前
        1
  •  6
  •   usr    6 年前

    不,在语言中没有办法静态地将其作为使用错误来捕获。

    您可以在运行时断言它,因为您已经在这样做了。不过,这与继承的精神背道而驰,因为一个基本的假设是派生类型必须替换基类型(Liskov替换原则)。

    Animal 一种新方法 abstract void Save() Dog 然后可以扔一个 NotSupportedException

        2
  •  2
  •   Mong Zhu Bart de Boer    6 年前

    是的,但是只有使用泛型和接口的解决方法。

    您需要做的是声明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; }
    }
    

    然后您可以使您的方法成为泛型的,并将类型仅约束到可以保存的aminals

    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
    

    this post

        3
  •  1
  •   Julo    6 年前

    没有标准的方法可以做到这一点,但是有一个简单的方法 (而且愚蠢) 解决方法。

    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错误。

    以下方法或属性之间的调用不明确:'程序.SaveAnimal(动物)“和”程序.SaveAnimal(无法保存)'

    记住,仍然可以使用 拯救动物 当你这样使用它的时候: SaveAnimal((Animal)dog)