Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/320.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用反射获取实现接口的所有类,并仅初始化与给定ID/opcode匹配的类_C#_Design Patterns_Reflection_Factory - Fatal编程技术网

C# 使用反射获取实现接口的所有类,并仅初始化与给定ID/opcode匹配的类

C# 使用反射获取实现接口的所有类,并仅初始化与给定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

因此,在下面的代码中,有一个指令接口,由许多类使用,例如AddInstruction、DividInstruction等。实现接口的每个类都根据指令接口分配标签和操作码

指令.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 //
            }
   }
说明工厂.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==操作码