代码之家  ›  专栏  ›  技术社区  ›  Dr. Strangelove

C#使用构造函数提供的策略模式初始化泛型类型

  •  0
  • Dr. Strangelove  · 技术社区  · 6 年前

    public class Operation<I> where I : IAnimal
    

    我定义了 IAnimal

    public interface IAnimal
    {
        string Name { get; }
    }
    

    我将类定义为:

    public class Dog : IAnimal
    {
        string Name { get; private set; }
    
        public Dog(string name)
        {
            Name = name;
        }
    }
    

    如果我想用 Dog Operation 类没有无参数构造函数,我利用策略模式如下:

    public interface IConstructor
    {
        IAnimal Construct(string name);
    }
    
    public class DogConstructor : IConstructor
    {
        IAnimal Construct(string name)
        {
            return new Dog(name);
        }
    }
    
    public class Operation<I> where I : IAnimal
    {
        public Operation() : this(new DogConstructor())
        { }
    
        public Operation(IConstructor constructor)
        {
            I animal = constructor.Construct("myDog"); // <<<<<<<< Error here!
        }
    }
    

    在市场上,我收到 Cannot implicitly convert type 'IAnimal' to 'I'. An explicit conversion exists (are you missing a cast?)

    I animal = (I)constructor.Construct("myDog"); ,全部工作。然而,我想知道为什么我需要投,而我有 where I : IAnimal

    4 回复  |  直到 6 年前
        1
  •  2
  •   Sweeper    6 年前

    然而,我想知道为什么我需要投,而我在哪里 I : IAnimal .

    是的,你保证过 I IAnimal 动物 它本身,但会是什么呢 Construct 返回? 构造 可能从返回不同的子类 .

    无论何时使用泛型,都应该记住泛型参数类型是由类/方法的客户机代码提供的,而不是由类/方法提供的。这是你的强迫 成为 Dog DogConstructor 如果没有,则传入参数。如果你这样做,那么它可能意味着泛型不适合这里。尝试删除它:

    public class Operation
    {
        public Operation() : this(new DogConstructor())
        { }
    
        public Operation(IConstructor constructor)
        {
            IAnimal animal = constructor.Construct("myDog");
        }
    }
    

    如果你坚持使用泛型,你不能假设 狗构造师 默认情况下,以及 IConstructor 也应该是通用的:

    public interface IConstructor<T> where I: IAnimal
    {
        T Construct(string name);
    }
    
    public class DogConstructor : IConstructor<Dog>
    {
        Dog Construct(string name)
        {
            return new Dog(name);
        }
    }
    
    public class Operation<I> where I : IAnimal
    {
        public Operation(IConstructor<I> constructor)
        {
            I animal = constructor.Construct("myDog");
        }
    }
    
    public class DogOperation: Operation<Dog> {
        public DogOperation() : base(new DogConstructor()) {}
    }
    

    因为Dog类没有无参数构造函数

    另一个解决方案可能是限制 所以它必须有一个无参数的构造函数,并在

    class Operation<I> where I : IAnimal, new() {
    
        2
  •  2
  •   ManishM    6 年前

    问题是编译器不知道要传递什么类来代替I。假设您创建了另一个类似于Dog的派生自Animal的类Cat。现在你用Cat代替I,按照代码这是可以的。但是构造函数。构造函数(“myDog”)是返回的狗,是猫的兄弟姐妹,不能解析成猫。所以错误会来的。看到代码了吗

    public interface IAnimal
    {
            string Name { get; }
    }
    
    public class Dog : IAnimal
    {
            public string Name { get; set; }
    
            public Dog(string name)
            {
                this.Name = name;
            }
    }
    
    public class Cat : IAnimal
    {
            public string Name { get; set; }
    
            public Cat(string name)
            {
                this.Name = name;
            }
    }
    
    public class Operation<I> where I : IAnimal
    {
            public Operation() : this(new DogConstructor())
            { }
    
            public Operation(IConstructor constructor)
            {
                I animal = constructor.Construct("myDog"); // <<<<<<<< Error here!
            }
    }
    

    检查以下代码。你正在经过一只猫,你想让它和狗一起被映射。那是行不通的。

    public class XYZ
    {
           public void MyMethod()
           {
                var obj = new Operation<Cat>();
           }
    }
    

    public class Operation<I> where I : IAnimal
    {
            public Operation() : this(new DogConstructor())
            { }
    
            public Operation(IConstructor constructor)
            {
                IAnimal animal = constructor.Construct("myDog"); // <<<<<<<< Error here!
            }
    }
    
        3
  •  1
  •   Thiago Barcala    6 年前

    IConstructor I . 你可以有一个 Operation<Cat> ,并传递给构造函数a DogConstructor

    你可以通过 IConstructor公司 泛型,并使操作构造函数接收 IConstructor<I>

        4
  •  1
  •   Z.R.T.    6 年前

    static void Main()
    {
        var operation = new Operation<Dog>("Jack");
        Console.WriteLine(operation.Animal.Name);
        Console.ReadLine();
    }
    
    public interface IAnimal
    {
        string Name { get; }
    }
    
    public class Dog : IAnimal
    {
        public string Name { get; private set; }
    
        public Dog()
        {
        }
    
        public Dog(string name)
        {
            Name = name;
        }
    }
    
    public class Operation<T> where T : IAnimal, new()
    {
        public T Animal { get; private set; }
    
        public Operation()
        {
            Animal = new T();
        }
    
        public Operation(params object[] args)
        {
            Animal = (T)Activator.CreateInstance(typeof(T), args);
        }
    }