我有3个项目:2个是类库,1个是控制台应用程序:
类库" AnimalManagers"。在AnimalManagers中是
public interface AnimalAgressiveBase{
string Bark<TAnimal>(TAnimal animal);
}
public abstract class AnimalAgressive<TEnemy> : AnimalAggresiveBase {
public abstract string BarkAtEnemy(TEnemy enemy);
public string Bark<TAnimal>(TAnimal animal){
return BarkAtEnemy((TEnemy)animal);// <---- Invalid cast exception even if type of object "animal" is Cat and we call this method from Dog class
}
}
public class AnimalManager {
public void WatchAnimal<TAnimalModel>
(TAnimalModel animalModel) { //<-- in example, animalModel is Cat("lucy")
var aggresiveAnimalDog = GetAgresiveAnimal(); //<-- returns object from dynamically loaded class Dog so this is basicaly new Dog() if animal models library class were referenced
if(aggresiveAnimalData != null) aggresiveAnimalDog .Bark(animalModel);
}
public AnimalAgressiveBase GetAgresiveAnimal(){
Assembly.LoadFrom("..\\AnimalModels.dll");
....
return aggresiveAnimal; //In This case Dog because he implements correct interface
}
}
类库&#34; AnimalModels&#34;在AnimalModels中是模型类Cat和Dog
public class Cat {
public string Name {get;set;}
}
public class Dog : AnimalAgressive<Cat> {
public override string BarkAtEnemy(Cat enemy){return enemy.Name;}
}
两个库都在ConsoleApp&#34; Zoo&#34; ,当我调用
时,我得到无效的类型异常var manager = new AnimalManager();
var manager.WatchAnimal(new Cat{Name="lucy"});
我得到了无效的强制转换异常,因为动态加载的程序集类型与引用的类型不相同,即使它们具有相同的AssemblyQualifiedName。
任何解决方案?目标是加载实现已知接口的汇编获取类型(例如:AnimalAggressiveBase)和调用我传递某种类型数据的方法。
答案 0 :(得分:0)
您的主要问题似乎是您在类型系统中没有代表您的动物的任何东西。你的班级Cat
如何与班级的其他层级结合?
public void WatchAnimal<TAnimalModel>
(TAnimalModel animalModel) { ... }
基本上TAnimalModel
可以是任何;我可以传递string
int
或Stream
,编译器也不会抱怨。您需要将TAnimalModel
保持为非常期望的内容,以便编译器可以推断您可以对animalModel
做什么或不做什么:
public void WatchAnimal<TAnimalModel>
(TAnimalModel animalModel) { ... } where TAnimalModel: AnimalBase
AnimalBase
可以是一个抽象基类,一个常规基类,一个接口,你有什么。唯一的条件是你所有的动物模型都需要实现它:
public class Cat: AnimalBase { ... }.
使用以下方法也会发生同样的事情:
public abstract class AnimalAgressive<TEnemy> : AnimalAggresiveBase { ... }
同样,这里TEnemy
可以是任何东西。这就是您在(TEnemy)animal
中收到编译时错误的原因。编译器无法验证转换是否有效,因此不允许它; 你知道TEnemy
将成为动物,但你还没有告诉编译器...所以告诉编译器添加一个constaint:
public abstract class AnimalAgressive<TEnemy> : AnimalAggresiveBase where TEnemy: AnimalBase { ... }
答案 1 :(得分:0)
性能昂贵的解决方案恕我直言。
[EDIT TO CLASS]
public abstract class AnimalAgressive<TEnemy> : AnimalAggresiveBase where TEnemy : class, new(){
[EDIT TO METHOD]
public string Bark<TAnimal>(TAnimal animal){
var typeAnimal = typeof(TAnimal);
var typeEnemy = typeof(TEnemy);
var propsAnimal = typeData.GetProperties();
var propsEnemy = typeGener.GetProperties();
var obj = new T();
foreach (var propertyInfo in propsAnimal)
{
var value = propertyInfo.GetValue(dataObject);
try
{
var propEnemy = propsEnemy.FirstOrDefault(x => x.Name.Equals(propertyInfo.Name, StringComparison.CurrentCulture));
propGener?.SetValue(obj, value, null);
}
catch (Exception)
{
throw;
}
}
return Bark(obj.Name);
答案 2 :(得分:0)
public interface IAnimalAgressive<in TAnimal>
{
string Bark(TAnimal animal);
}
public abstract class AnimalAggressiveBase<TEnemy> : IAnimalAgressive<TEnemy>
{
public abstract string BarkAtEnemy(TEnemy enemy);
public string Bark(TEnemy enemy)
{
return BarkAtEnemy(enemy);
}
}
你的动物经理然后变成:
public class AnimalManager
{
public void WatchAnimal<TAggressiveAnimal, TAnimal>
(TAggressiveAnimal aggressive, TAnimal enemy)
where TAggressiveAnimal : IAnimalAgressive<TAnimal>
{
Console.WriteLine(aggressive.Bark(enemy));
}
}
现在它的责任是Dog和Cat符合AnimalManager的期望,我现在会保持简单:
using System.ComponentModel.Composition;
namespace AnimalModels
{
[Export(typeof(Cat))]
public class Cat
{
public string Name { get; set; }
}
}
和狗变成:
using AnimalManagers;
using System.ComponentModel.Composition;
namespace AnimalModels
{
[Export(typeof(AnimalAggressiveBase<Cat>))]
public class Dog : AnimalAggressiveBase<Cat>
{
public override string BarkAtEnemy(Cat enemy)
{
return enemy.Name;
}
}
}
现在的诀窍是编写相关类型的整个目录,因此对于我们的控制台应用程序,我们创建了另一种类型,用于从我们导出的类型目录中管理这些关系:
public class TypeManager
{
public void Compose()
{
try
{
var directoryPath = Path.GetFullPath(".");
var aggregateCatalog = new AggregateCatalog();
aggregateCatalog.Catalogs.Add(new DirectoryCatalog(directoryPath, "*.dll"));
//Create the composition container
var container = new CompositionContainer(aggregateCatalog);
container.ComposeParts(this);
var cat = container.GetExportedValue<Cat>();
cat.Name = "lucy";
var dog = container.GetExportedValue<AnimalAggressiveBase<Cat>>();
var manager = new AnimalManager();
manager.WatchAnimal(dog, cat);
}
catch (CompositionException compositionException)
{
Console.WriteLine(compositionException.ToString());
throw;
}
}
}
现在我们需要做的就是像这样运行Main方法:
static void Main(string[] args)
{
TypeManager tm = new TypeManager();
tm.Compose();
}
现在导出的类型将自动在typemanager中创建,我们不必担心反射。
答案 3 :(得分:-1)
public interface AnimalAgressiveBase<TAnimal>
{
string Bark(TAnimal animal);
}
public abstract class AnimalAgressive<TEnemy, TAnimal> : AnimalAgressiveBase<TAnimal> where TEnemy : TAnimal
{
public abstract string BarkAtEnemy(TEnemy enemy);
public string Bark(TAnimal animal)
{
return BarkAtEnemy((TEnemy)animal);
}
}