如何将使用 Activator.CreateInstance 创建的对象句柄解包到基础 class?
How to unwrap object handle created with Activator.CreateInstance to the base class?
在我之前的 中,我想强制所有派生的 classes 实现它们自己的选项 class。给定的答案为我的问题提供了解决方案,但随后又产生了另一个问题,因为我无法再打开对象句柄。
我创建了一个空的 public 接口和一个实现它的 class:
public interface IOptions{};
public class SearchOptions : IOptions
{
public Boolean SearchHiddenFiles { get; set; }
public Boolean CaseSensitive { get; set; }
}
然后我创建了一个基础 class,带有一个抽象参数 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();
}
最后,我创建了一堆 classes 扩展任务 class,即:
public class TaskSearch : Task <SearchOptions>
{
public override SearchOptions TaskOptions { get; set; }
public override void Execute()
{
Console.Write("Search running");
}
}
主程序初始化一个 Job 对象,该对象接受一个具有 json 符号的文件,该符号定义了 id、名称等以及任务。
最后,这是工作 class:
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);
}
}
}
}
在我更改任务 class 以实现 IOptions 接口之前,我将其解包为:
var task = (Task)taskobj.Unwrap();
有效,但在添加 IOptions
并将其转换为 Task<IOptions>
后,它抛出 System.InvalidCastException 错误,因为 taskobj 是 TaskSearch(不是 Task)。
如果我手动输入 Task<SearchOptions>
,它会展开,但会在末尾抱怨 Tasks 列表,因为它现在不是 Task<IOptions>
的类型。
我需要使 Tasks 列表通用,以便它接受所有派生的 classes 并在解包 taskobj 或从 task 获取类型参数之前找到一种获取类型参数的方法class 保存当前任务名称的字符串。
如果必须的话,我会为选项创建一个字典,但这就是我想要实现它的方式,我想知道我是否可以。
谢谢
我没有隐式定义任务对象,而是将其显式定义为动态类型。
dynamic task = taskobj.Unwrap();
没有转换,编译器不会抱怨它,因为它是动态的,并且它知道它在运行时是 TaskSearch。
在我之前的
我创建了一个空的 public 接口和一个实现它的 class:
public interface IOptions{};
public class SearchOptions : IOptions
{
public Boolean SearchHiddenFiles { get; set; }
public Boolean CaseSensitive { get; set; }
}
然后我创建了一个基础 class,带有一个抽象参数 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();
}
最后,我创建了一堆 classes 扩展任务 class,即:
public class TaskSearch : Task <SearchOptions>
{
public override SearchOptions TaskOptions { get; set; }
public override void Execute()
{
Console.Write("Search running");
}
}
主程序初始化一个 Job 对象,该对象接受一个具有 json 符号的文件,该符号定义了 id、名称等以及任务。
最后,这是工作 class:
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);
}
}
}
}
在我更改任务 class 以实现 IOptions 接口之前,我将其解包为:
var task = (Task)taskobj.Unwrap();
有效,但在添加 IOptions
并将其转换为 Task<IOptions>
后,它抛出 System.InvalidCastException 错误,因为 taskobj 是 TaskSearch(不是 Task)。
如果我手动输入 Task<SearchOptions>
,它会展开,但会在末尾抱怨 Tasks 列表,因为它现在不是 Task<IOptions>
的类型。
我需要使 Tasks 列表通用,以便它接受所有派生的 classes 并在解包 taskobj 或从 task 获取类型参数之前找到一种获取类型参数的方法class 保存当前任务名称的字符串。
如果必须的话,我会为选项创建一个字典,但这就是我想要实现它的方式,我想知道我是否可以。
谢谢
我没有隐式定义任务对象,而是将其显式定义为动态类型。
dynamic task = taskobj.Unwrap();
没有转换,编译器不会抱怨它,因为它是动态的,并且它知道它在运行时是 TaskSearch。