我有一个在泛型类型上运行的类:
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
,因为Dog
类没有无参数构造函数,所以我利用策略模式如下:
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
。
但是,我想知道为什么我需要施放,而我有
I : IAnimal
。
是的,你确实保证I
将成为IAnimal
或IAnimal
本身的子类,但Construct
将返回什么? Construct
可能会从I
返回一个不同的子类。
无论何时使用泛型,都应该记住泛型参数类型是由类/方法的客户端代码提供的,而不是类/方法。如果没有传入参数,你在这里使用I
强迫Dog
成为DogConstructor
。如果你这样做,那么它可能意味着泛型不适合这里。尝试删除它:
public class Operation
{
public Operation() : this(new DogConstructor())
{ }
public Operation(IConstructor constructor)
{
IAnimal animal = constructor.Construct("myDog");
}
}
现在,如果你坚持使用泛型,你不能默认假设一个DogConstructor
,而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类没有参数构造函数
另一种解决方案可能是约束I
,使其必须具有无参数构造函数,并将其添加到Dog
:
class Operation<I> where I : IAnimal, new() {
问题是编译器不知道你要通过什么类来代替我。假设你创建了另一个类派生自Cat的类似于Dog的类。现在你将Cat in Operation代替我,这很好,按照代码。但构造函数.Construct(“myDog”)正在返回Dog,它是Cat的兄弟,并且无法解析为Cat。所以会出现错误。看代码
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!
}
}
检查以下代码。你正在传递Cat,你希望它与Dog一起映射。那不行。
public class XYZ
{
public void MyMethod()
{
var obj = new Operation<Cat>();
}
}
如果你知道它将构造.Construct(“myDog”)返回动物然后用IAnimal替换我。这样编译器就可以确定要从constructor.Construct(“myDog”)中设置返回对象的引用
public class Operation<I> where I : IAnimal
{
public Operation() : this(new DogConstructor())
{ }
public Operation(IConstructor constructor)
{
IAnimal animal = constructor.Construct("myDog"); // <<<<<<<< Error here!
}
}
问题是,不能保证你的IConstructor
将返回与I
相同的类。你可以有一个Operation<Cat>
,并传递给构造函数DogConstructor
。
您也可以通过使IConstructor
通用来解决这个问题,并使Operation构造函数接收IConstructor<I>
。
我面临同样的问题,我使用Activator.CreateInstance(Type type,params object [] args)
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);
}
}