动态类型传递和实例化——如何

本文关键字:实例化 如何 类型 动态 | 更新日期: 2023-09-27 18:01:55

编辑:更改Activator,仍不工作

我对c#非常(非常)陌生,我很确定这是一个骗局,但是我已经看了前面的问题,我仍然不能算出所有的要点。

我试图通过用泛型列表上的映射替换一些重复的代码来减少代码气味。具体来说,我的代码看起来像

var fooNode = node as IFoo;
var barNode = node as IBar;
var bazNode = node as IBaz;
...
if(fooNode != null)
    return new FooThing();
if(barNode != null)
    return new BarThing();
if(bazNode != null)
    return new BazThing();
...

我想概括一下


这是我的尝试:

var types = new Dictionary<Type, Type>
{
    {typeof(IFoo), typeof(FooThing)},
    {typeof(IBar), typeof(BarThing)},
    ...
}
foreach(var entry in types)
{
    var castNode = node as entry.Key;
    return Activator.CreateInstance(entry.Value);
}

自然地,它不起作用:The type or namespace name 'entry' could not be found (are you missing a using directive or an assembly reference?)。你能帮忙吗?这种事情在c#中可能实现吗?

动态类型传递和实例化——如何

这个怎么样?

foreach(var entry in types)
{
    if (node != null && entry.Key.IsAssignableFrom(node.GetType()))
    {
        return Activator.CreateInstance(entry.Value);
    }
}

问题是你混淆了泛型类型参数和运行时类型,特别是Type类。

如果您在编译时知道类型是什么,那么您可以使用泛型Activator.CreateInstance<T>()方法来创建底层对象的实例—您可以使用类型参数之类的东西,以便这行代码不需要知道类型是什么,例如:

T CreateObject<T>()
{
    return Activator.CreateInstance<T>();
}

然而,这只是推卸责任。为了调用这个方法,类型参数T的值必须在某处提供——无论哪种方式,编译器都必须能够将T解析为类型(而不是变量或方法)。

相反,Type类在运行时对类型信息进行编码,例如它的名称或类型声明所在的程序集。Activator.CreateInstance还带有一个重载,允许您提供Type的实例:

object CreateObject(Type type)
{
    return Activator.CreateInstance(type);
}

在你的情况下,看起来你不知道编译时的类型是什么,所以你将主要使用Type类-你可以使用typeof(MyClass)来获得相应的Type的实例,用于在运行时已知的类,myObject.GetType()来获取运行时对象的类型信息。

var types = new Dictionary<Type, Type>
{
    {typeof(IFoo), typeof(FooThing)},
    {typeof(IBar), typeof(BarThing)},
    ...
}
foreach(var entry in types)
{
    if(entry.Key.IsAssignableFrom(node.GetType()))
       return Activator.CreateInstance(entry.Value);
}
return null;

如果不清楚地理解您希望从同一操作返回不同类型的目的,将很难提供帮助。也许你想要解决的问题的一些背景信息?

我将假设,因为您试图交替返回它们,所以fooThing, barthing和BazThing具有相同的接口。所以我假设如下:

 public class FooThing : IMyOperations
 {
 }
 public class BarThing : IMyOperations
 {
 }
 public class BazThing : IMyOperations
 {
 }

可以在另一个接口中定义类之间的关系

 public interface IMyChoice
 {
      public bool IsSelected { get; }
      public IMyOperations GetWorker();
 } 
 public class ChoiceFoo : IMyChoice
 {

 }
 public class ChoiceBar : IMyChoice
 {
 }
 public class ChoiceBaz : IMyChoice
 {
 }

现在你可以说

 foreach( var entry in choices)
 {
    if(entry.IsSelected)
    {
         return entry.GetWorker();
         //Can't remember if i need to break after return..doubt it
    }
 }