C# 使用策略模式提供的构造函数初始化泛型类型
C# initialize a generic type using a strategy-pattern-provided constructor
我有一个在通用类型上运行的 class:
public class Operation<I> where I : IAnimal
我定义 IAnimal
如下:
public interface IAnimal
{
string Name { get; }
}
我定义一个class如下:
public class Dog : IAnimal
{
string Name { get; private set; }
public Dog(string name)
{
Name = name;
}
}
如果我想在Operation
class中使用Dog
,因为Dog
class没有无参构造函数,我杠杆策略模式如下:
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
时还需要施法。
问题是无法保证您的 IConstructor
将 return 与 I
相同 class。您可以有一个 Operation<Cat>
,然后将 DogConstructor
传递给构造函数。
您也可以通过使 IConstructor
泛化来解决此问题,并使 Operation 构造函数接收 IConstructor<I>
。
However, I am wondering why do I need to cast while I have where I : IAnimal
.
是的,您确实保证 I
将是 IAnimal
或 IAnimal
本身的子类,但是 Construct
return 会是什么? Construct
可能 return 与 I
不同的子类。
无论何时使用泛型,都应该记住泛型参数类型是由 class/method 的客户端代码提供的,而不是由 class/method 的客户端代码提供的。如果没有传入参数,您在这里通过使用 DogConstructor
强制 I
成为 Dog
。如果您这样做,那么这可能意味着泛型在这里不适合。尝试删除它:
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()) {}
}
since the Dog class does not have a parameter-less constructor
另一种解决方案可能是约束 I
使其必须具有无参数构造函数,并向 Dog
:
添加一个
class Operation<I> where I : IAnimal, new() {
我遇到了同样的问题,我使用了 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);
}
}
问题是编译器不知道你要传递什么 Class 来代替 I。假设你创建另一个 class Cat 派生自类似于 Dog 的 Animal。现在您在 Operation 中传递 Cat 来代替 I,这根据代码是没问题的。但是 constructor.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>();
}
}
如果你知道它会 constructor.Construct("myDog") returns 动物然后用 IAnimal 替换 I。这样编译器就可以确定要设置 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!
}
}
我有一个在通用类型上运行的 class:
public class Operation<I> where I : IAnimal
我定义 IAnimal
如下:
public interface IAnimal
{
string Name { get; }
}
我定义一个class如下:
public class Dog : IAnimal
{
string Name { get; private set; }
public Dog(string name)
{
Name = name;
}
}
如果我想在Operation
class中使用Dog
,因为Dog
class没有无参构造函数,我杠杆策略模式如下:
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
时还需要施法。
问题是无法保证您的 IConstructor
将 return 与 I
相同 class。您可以有一个 Operation<Cat>
,然后将 DogConstructor
传递给构造函数。
您也可以通过使 IConstructor
泛化来解决此问题,并使 Operation 构造函数接收 IConstructor<I>
。
However, I am wondering why do I need to cast while I have where
I : IAnimal
.
是的,您确实保证 I
将是 IAnimal
或 IAnimal
本身的子类,但是 Construct
return 会是什么? Construct
可能 return 与 I
不同的子类。
无论何时使用泛型,都应该记住泛型参数类型是由 class/method 的客户端代码提供的,而不是由 class/method 的客户端代码提供的。如果没有传入参数,您在这里通过使用 DogConstructor
强制 I
成为 Dog
。如果您这样做,那么这可能意味着泛型在这里不适合。尝试删除它:
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()) {}
}
since the Dog class does not have a parameter-less constructor
另一种解决方案可能是约束 I
使其必须具有无参数构造函数,并向 Dog
:
class Operation<I> where I : IAnimal, new() {
我遇到了同样的问题,我使用了 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);
}
}
问题是编译器不知道你要传递什么 Class 来代替 I。假设你创建另一个 class Cat 派生自类似于 Dog 的 Animal。现在您在 Operation 中传递 Cat 来代替 I,这根据代码是没问题的。但是 constructor.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>();
}
}
如果你知道它会 constructor.Construct("myDog") returns 动物然后用 IAnimal 替换 I。这样编译器就可以确定要设置 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!
}
}