C# 使用反射获取实现接口的所有类,并仅初始化与给定ID/opcode匹配的类
因此,在下面的代码中,有一个指令接口,由许多类使用,例如AddInstruction、DividInstruction等。实现接口的每个类都根据指令接口分配标签和操作码 指令.csC# 使用反射获取实现接口的所有类,并仅初始化与给定ID/opcode匹配的类,c#,design-patterns,reflection,factory,C#,Design Patterns,Reflection,Factory,因此,在下面的代码中,有一个指令接口,由许多类使用,例如AddInstruction、DividInstruction等。实现接口的每个类都根据指令接口分配标签和操作码 指令.cs public abstract class Instruction { private string label; private string opcode; protected Instruction(string label, string opcode
public abstract class Instruction
{
private string label;
private string opcode;
protected Instruction(string label, string opcode)
{
this.label = label;
this.opcode = opcode;
}
public abstract void Execute(Machine m);
}
public class AddInstruction : Instruction
{
private int reg, s1, s2;
public AddInstruction(string lab, int reg, int s1, int s2) : base(lab, "add") // here the base interface is Instruction and we are assigning the opcode as add, other instructions have there own opcodes //
{
this.reg = reg;
this.s1 = s1;
this.s2 = s2;
}
public override void Execute(Machine m) =>
// do something
}
interface InstructionFactoryInterface
{
Instruction GetInstruction(string opcode);
}
class InstructionFactory : InstructionFactoryInterface
{
public Instruction GetInstruction(string opcode)
{
Type type = typeof(Instruction);
var types = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => type.IsAssignableFrom(p));
foreach (var type1 in types)
{
// loop through all the types and only return the class that has a matching opcode //
}
}
具有相同基本功能的多条指令之一的示例
附加说明.cs
public abstract class Instruction
{
private string label;
private string opcode;
protected Instruction(string label, string opcode)
{
this.label = label;
this.opcode = opcode;
}
public abstract void Execute(Machine m);
}
public class AddInstruction : Instruction
{
private int reg, s1, s2;
public AddInstruction(string lab, int reg, int s1, int s2) : base(lab, "add") // here the base interface is Instruction and we are assigning the opcode as add, other instructions have there own opcodes //
{
this.reg = reg;
this.s1 = s1;
this.s2 = s2;
}
public override void Execute(Machine m) =>
// do something
}
interface InstructionFactoryInterface
{
Instruction GetInstruction(string opcode);
}
class InstructionFactory : InstructionFactoryInterface
{
public Instruction GetInstruction(string opcode)
{
Type type = typeof(Instruction);
var types = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => type.IsAssignableFrom(p));
foreach (var type1 in types)
{
// loop through all the types and only return the class that has a matching opcode //
}
}
从这里开始,我想使用工厂模式和反射,以便在将来可以根据提供的操作码启动具有自己操作码的新指令
说明工厂界面.cs
public abstract class Instruction
{
private string label;
private string opcode;
protected Instruction(string label, string opcode)
{
this.label = label;
this.opcode = opcode;
}
public abstract void Execute(Machine m);
}
public class AddInstruction : Instruction
{
private int reg, s1, s2;
public AddInstruction(string lab, int reg, int s1, int s2) : base(lab, "add") // here the base interface is Instruction and we are assigning the opcode as add, other instructions have there own opcodes //
{
this.reg = reg;
this.s1 = s1;
this.s2 = s2;
}
public override void Execute(Machine m) =>
// do something
}
interface InstructionFactoryInterface
{
Instruction GetInstruction(string opcode);
}
class InstructionFactory : InstructionFactoryInterface
{
public Instruction GetInstruction(string opcode)
{
Type type = typeof(Instruction);
var types = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => type.IsAssignableFrom(p));
foreach (var type1 in types)
{
// loop through all the types and only return the class that has a matching opcode //
}
}
说明工厂.cs
public abstract class Instruction
{
private string label;
private string opcode;
protected Instruction(string label, string opcode)
{
this.label = label;
this.opcode = opcode;
}
public abstract void Execute(Machine m);
}
public class AddInstruction : Instruction
{
private int reg, s1, s2;
public AddInstruction(string lab, int reg, int s1, int s2) : base(lab, "add") // here the base interface is Instruction and we are assigning the opcode as add, other instructions have there own opcodes //
{
this.reg = reg;
this.s1 = s1;
this.s2 = s2;
}
public override void Execute(Machine m) =>
// do something
}
interface InstructionFactoryInterface
{
Instruction GetInstruction(string opcode);
}
class InstructionFactory : InstructionFactoryInterface
{
public Instruction GetInstruction(string opcode)
{
Type type = typeof(Instruction);
var types = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => type.IsAssignableFrom(p));
foreach (var type1 in types)
{
// loop through all the types and only return the class that has a matching opcode //
}
}
现在我要做的是,如何循环实现指令接口的所有类型,并只返回与传入的操作码参数匹配的类型。谢谢这有点棘手,因为
AddInstruction
没有默认构造函数。尽管如此,这是可以做到的。您需要使用FormatterServices.GetUninitializedObject()
来获取实例,而不使用构造函数。基类指令
也需要修改,因此操作码
不是字段,而是在每个子类中实现的方法。以下是一个例子:
using System;
using System.Runtime.Serialization;
namespace Generator
{
public class Program
{
public static void Main()
{
var add = FormatterServices.GetUninitializedObject(typeof(AddInstruction));
var opcode = ((Instruction) add).GetOpCode();
Console.WriteLine(opcode);
}
}
public abstract class Instruction
{
public abstract string GetOpCode();
}
public class AddInstruction : Instruction
{
private int s1, s2;
public AddInstruction(int s1, int s2)
{
this.s1 = s1;
this.s2 = s2;
}
public override string GetOpCode()
{
return "add";
}
}
}
使用字典和注册已知操作以及工厂方法(或委托)更容易 然后你就可以得到一个指令
public Instruction GetInstruction(string opcode, string lab, int reg, int s1, int s2)
{
if (FactoryDict.TryGetValue(opcode, out var create)) {
return create(lab, reg, s1, s2);
}
return null;
}
如果使用命名约定,例如,指令类的名称是带有大写首字母+“指令”的操作码,则可以使用反射:
另外,始终使用具有标准化参数列表的构造函数会使事情变得更容易。System.Reflection API不允许您从构造函数主体获取IL指令。因此,您无法确定特定类的构造函数传递给基构造函数的参数 您可以使用库(也可以与.NET Framework一起使用)完成此任务
类指令工厂:指令工厂界面{
静态只读IDictionary指令=新字典();
静态指令工厂(){
初始化指令();
}
静态无效初始化指令(){
类型=类型(指令);
var types=AppDomain.CurrentDomain.GetAssemblys()
.SelectMany(s=>s.GetTypes())
其中(p=>type.IsAssignableFrom(p));
foreach(类型中的变量type1){
试一试{
字符串type1Opcode=GetOpcode(type1);
说明.添加(类型1密码,类型1);
}捕获(无效操作异常ex){
对数误差(ex);
}
}
}
静态无效日志错误(InvalidOperationException ex){
// ...
}
公共指令GetInstruction(字符串操作码,参数对象[]args){
类型指令类型;
bool found=指令.TryGetValue(操作码,out指令类型);
如果(!找到){
抛出新的InvalidOperationException($“未找到指令{opcode}”);
}
return(指令)Activator.CreateInstance(指令类型,args);
}
静态只读IDictionary AssemblyDefinitions=new Dictionary();
静态AssemblyDefinition GetAssemblyDefinition(类型){
定义广告;
bool found=AssemblyDefinitions.TryGetValue(type.Assembly.Location,out ad);
如果(!找到){
ad=AssemblyDefinition.ReadAssembly(类型.Assembly.Location);
AssemblyDefinitions.Add(type.Assembly.Location,ad);
}
返回广告;
}
静态字符串GetOpcode(类型){
AssemblyDefinition adType=GetAssemblyDefinition(类型);
TypeDefinition tdType=adType.MainModule.GetType(type.FullName);
IEnumerable-ctors=tdType.GetConstructors();
AssemblyDefinition adInstruction=GetAssemblyDefinition(指令类型));
TypeDefinition tdInstruction=adInstruction.MainModule.GetType(typeof(Instruction).FullName);
MethodDefinition=tInstruction.GetConstructors().Single();
foreach(方法定义-系数中的系数){
for(int i=0;i
如何使用属性?它对于未来是非常可扩展的。尽管操作码只是一个字符串,但您必须注意字符串比较和唯一性,因为将来可能会有两个类共享相同的操作码
自定义属性类:
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class InstructionAttribute : Attribute
{
public string OpCode { get; private set; } = string.Empty;
public InstructionAttribute(string opCode)
{
OpCode = opCode;
}
}
标记派生类:
[Instruction("the opCode associated with this type")]
public class AddInstruction : Instruction
{
// rest of class
}
对使用属性查找所需类型的InstructionFactory所做的更改:
class InstructionFactory : InstructionFactoryInterface
{
public Instruction GetInstruction(string opcode)
{
Type type = typeof(Instruction);
var types = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => type.IsAssignableFrom(p));
foreach (var type1 in types)
{
var att = type1.GetCustomAttribute<InstructionAttribute>(false); // don't check ancestors; only this type
string attributeOpCode = att?.OpCode;
if (!string.IsNullOrWhiteSpace(attributeOpCode) && attributeOpCode == opcode)
{
// construct an instance of type1 however you prefer, return it
}
}
return null; // or other error handling
}
}
类指令工厂:指令工厂界面
{
公共指令GetInstruction(字符串操作码)
{
类型=类型(指令);
var types=AppDomain.CurrentDomain.GetAssemblys()
.SelectMany(s=>s.GetTypes())
其中(p=>type.IsAssignableFrom(p));
foreach(类型中的变量type1)
{
var att=type1.GetCustomAttribute(false);//不检查祖先;仅检查此类型
字符串attributeOpCode=att?.OpCode;
如果(!string.IsNullOrWhiteSpace(attributeOpCode)&&attributeOpCode==操作码