【问题标题】:How to unwrap object handle created with Activator.CreateInstance to the base class?如何将使用 Activator.CreateInstance 创建的对象句柄解包到基类?
【发布时间】:2015-02-17 16:12:10
【问题描述】:

在我之前的question 中,我想强制所有派生类实现它们自己的选项类。给定的答案为我的问题提供了解决方案,但随后又产生了另一个问题,因为我无法再打开对象句柄了。

我创建了一个空的公共接口和一个实现它的类:

public interface IOptions{};

public class SearchOptions : IOptions
{
    public Boolean SearchHiddenFiles { get; set; }
    public Boolean CaseSensitive { get; set; }
}

然后我创建了一个带有抽象参数TaskOptions 的基类,它是 IOptions 的类型:

public abstract class Task<T> where T : IOptions
{
  public string ID {get; set;}
  public string Name {get; set;}

  public abstract T TaskOptions { get; set; }
  public abstract void Execute();
}

最后,我创建了一堆扩展 Task 类的类,即:

public class TaskSearch : Task <SearchOptions>
{
    public override SearchOptions TaskOptions { get; set; }
    public override void Execute()
    {
        Console.Write("Search running");
    }
}

主程序初始化一个 Job 对象,该对象接受一个文件,该文件具有定义 id、name 等的 json 符号以及任务。

最后,这里是作业类:

public class Job
{
    public String Name { get; set; }
    public String Description { get; set; }
    public List<Task<IParameters>> Tasks { get; set; }
    public Job(string JsonFile)
    {        
        using (StreamReader file = File.OpenText(JsonFile))
        {
            string json = file.ReadToEnd();
            JObject o = JObject.Parse(json);

            this.Name = o.SelectToken("Name").ToString();
            this.Description = o.SelectToken("Description").ToString();

            JArray arr = (JArray)o["Tasks"];

            foreach (var t in arr)
            {
                var taskclass = t["Name"].ToString();

                var taskobj = Activator.CreateInstance("RunTasks", "RunTasks." + taskclass);

                var task = (Task<IParameters>)taskobj.Unwrap(); //<-- throws System.InvalidCastException because taskobj is TaskSearch
                // set task.ID, task.Name, etc..
                //...
                //...
                Tasks.Add(task);
            }
        }
    }
}

在我更改 Task 类以实现 IOptions 接口之前,我将其解包为:

var task = (Task)taskobj.Unwrap();

这有效,但在添加 IOptions 并将其转换为 Task&lt;IOptions&gt; 后,它会引发 System.InvalidCastException 错误,因为 taskobj 是 TaskSearch(不是 Task)。

如果我手动输入 Task&lt;SearchOptions&gt;,它会解开包装,但会在末尾抱怨 Tasks 列表,因为它现在不是 Task&lt;IOptions&gt; 的类型。 我需要使 Tasks 列表成为通用列表,以便它接受所有派生类并找到一种方法来获取类型参数,然后再展开 taskobj 或从保存当前任务的 taskclass 字符串中获取它名字。

如果需要,我会为选项创建一个字典,但这就是我想要实现它的方式,我想知道是否可以。

谢谢

【问题讨论】:

    标签: c# derived-class createinstance


    【解决方案1】:

    我没有隐式定义任务对象,而是将其显式定义为动态类型。

    dynamic task = taskobj.Unwrap();
    

    如果不进行强制转换,编译器不会抱怨它,因为它是动态的,并且在运行时它知道它是 TaskSearch。

    【讨论】:

      猜你喜欢
      • 2021-07-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-06
      • 2017-05-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-18
      相关资源
      最近更新 更多