C# 在应用程序初始化时注册工厂函数

C# 在应用程序初始化时注册工厂函数,c#,initialization,C#,Initialization,对于我正在编写的服务器,我有一个文件文件夹,每个文件中有一个类。 每个类表示来自客户端的请求操作。 如果我添加了一个新操作,我只希望能够添加一个新文件,让文件自己注册 在像这样的语言中,您可以拥有init函数,每个文件中有一个函数,在初始化时运行,允许您注册工厂委托(或一级函数)之类的东西 你能在C#中实现类似的功能吗?让这些文件注册它们自己的类,而不必编辑第二个包含所有已注册操作列表的文件 // This won't work, but how to do it? func init() {

对于我正在编写的服务器,我有一个文件文件夹,每个文件中有一个类。
每个类表示来自客户端的请求操作。
如果我添加了一个新操作,我只希望能够添加一个新文件,让文件自己注册

在像这样的语言中,您可以拥有
init
函数,每个文件中有一个函数,在初始化时运行,允许您注册工厂委托(或一级函数)之类的东西

你能在C#中实现类似的功能吗?让这些文件注册它们自己的类,而不必编辑第二个包含所有已注册操作列表的文件

// This won't work, but how to do it?
func init() {
    // Registering a factory function to a Dictionary<string, Func<IAction>>
    Reg.ClassDictionary.Add("connect", () => { return new Connect(); });
}

namespace Action
{
    class Connect : IAction
    {
         [JsonProperty("user")]
        public string Username;

        [JsonProperty("pass")]
        public string Password;

        public bool Exec()
        {
            return ConnectToServer(Username, Password);
        }
    }
}
//这行不通,但怎么做呢?
func init(){
//将工厂函数注册到字典
Reg.ClassDictionary.Add(“connect”,()=>{returnnewconnect();});
}
命名空间操作
{
类连接:IAction
{
[JsonProperty(“用户”)]
公共字符串用户名;
[JsonProperty(“通行证”)]
公共字符串密码;
公共图书馆行政主任
{
返回ConnectToServer(用户名、密码);
}
}
}

如果它是一个控制台应用程序,只需在
Main
方法的开头执行即可

如果它是windows服务,当您扩展
ServiceBase
时,您会得到一个
OnStart
方法(您可以覆盖该方法),该方法在服务启动时执行

以下是有关Windows服务的快速教程,可帮助您入门:


编辑:根据您的澄清,抱歉,没有内置的方式让文件/类型按您的要求执行。然而,你可以做的是一些反思。您可以仔细阅读程序集,以了解实现
IAction
(或者更确切地说,一些其他描述性类型)的特定类型/接口。您可以搜索所有这些应用程序,实例化它们,然后在我上面描述的启动阶段调用它们的各种
init
方法。

如果是控制台应用程序,只需在
Main
方法的开始处执行即可

如果它是windows服务,当您扩展
ServiceBase
时,您会得到一个
OnStart
方法(您可以覆盖该方法),该方法在服务启动时执行

以下是有关Windows服务的快速教程,可帮助您入门:


编辑:根据您的澄清,抱歉,没有内置的方式让文件/类型按您的要求执行。然而,你可以做的是一些反思。您可以仔细阅读程序集,以了解实现
IAction
(或者更确切地说,一些其他描述性类型)的特定类型/接口。您可以搜索所有这些方法,实例化它们,然后在我上面描述的启动阶段调用它们的各种
init
方法。

您可以在类上使用静态初始值设定项

namespace Action
{
    class Connect : IAction
    {
        static Connect ()
        {
            Reg.ClassDictionary.Add("connect", () => { return new Connect(); });
        }

        [JsonProperty("user")]
        public string Username;

        [JsonProperty("pass")]
        public string Password;

        public bool Exec()
        {
            return ConnectToServer(Username, Password);
        }
    }
}

可以在类上使用静态初始值设定项

namespace Action
{
    class Connect : IAction
    {
        static Connect ()
        {
            Reg.ClassDictionary.Add("connect", () => { return new Connect(); });
        }

        [JsonProperty("user")]
        public string Username;

        [JsonProperty("pass")]
        public string Password;

        public bool Exec()
        {
            return ConnectToServer(Username, Password);
        }
    }
}

这取决于你们的集会是如何组织的,但这里有一种方法。 定义自定义属性 调用say MyTask,这样您就可以识别感兴趣的程序集中的所有类,并且在您的示例中要公开的名称是“connect”

然后使用反射来钳制组件,找到您想要的CHAP并注册它们

不知道您对属性和refelection了解多少

但这是我的一个

[System.AttributeUsage(System.AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
public sealed class ConversionAttribute : System.Attribute
{
    public string DatabaseName { get; set; }
    public bool ReadOnly { get; set; }
    public int ConversionOrder { get; set; }
    public String VersionStart { get; set; }
    public String VersionEnd { get; set; }
}
一个班级被这样标记

[Conversion(ConversionOrder = 14)]
public class ConversionExample : DataConversion
这一章将遍历程序集抓取任何标记为ConversionAttribute的对象,实例化它,然后调用一个方法

public static void DoConversions()
{
    Type[] contents = CommandLine.Instance.TaskAssembly.GetExportedTypes();
    SortedDictionary<int, List<Type>> conversions = new SortedDictionary<int, List<Type>>();
    foreach (Type t in contents)
    {
        ConversionAttribute attr = FindAttribute(t);
        if (attr != null)
        {
            if (!conversions.ContainsKey(attr.ConversionOrder))
            {
                 conversions.Add(attr.ConversionOrder, new List<Type>());
            }
            conversions[attr.ConversionOrder].Add(t);
        }
    }

    foreach (int order in conversions.Keys)
    {
        foreach (Type t in conversions[order])
        {
            ConstructorInfo c = t.GetConstructor(new Type[] { typeof(CommandLine) });
            DataConversion d = (DataConversion)c.Invoke(new object[] { CommandLine.Instance });
            ConversionVersionStatus status = d.VersionStatus(CommandLine.Instance.TaskParameterValue("TAX_FULL_VERSION"));
            if ((status == ConversionVersionStatus.NoVersionSet) || (status == ConversionVersionStatus.Relevant))
            {
                d.Log(String.Format(CultureInfo.InvariantCulture, "Started Conversion {0}", d.FriendlyName));
                d.ExecuteTask();
                d.Log(String.Format(CultureInfo.InvariantCulture, "Finished Conversion {0}", d.FriendlyName));
           }
           else
           {
               if (status == ConversionVersionStatus.Discontinued)
               {
                   d.Log(String.Format(CultureInfo.InvariantCulture, "Conversion {0} skipped as discontinued", d.FriendlyName));
               }
               else
               {
                   d.Log(String.Format(CultureInfo.InvariantCulture, "Conversion {0} skipped as not yet relevant", d.FriendlyName));
               }
           }
       }
   }
}
publicstaticvoiddoconversions()
{
类型[]contents=CommandLine.Instance.TaskAssembly.GetExportedTypes();
SortedDictionary转换=新的SortedDictionary();
foreach(目录中的类型t)
{
转换属性attr=FindAttribute(t);
如果(attr!=null)
{
如果(!conversions.ContainsKey(attr.ConversionOrder))
{
Add(attr.ConversionOrder,new List());
}
转换[attr.ConversionOrder].Add(t);
}
}
foreach(在conversions.Keys中的整数顺序)
{
foreach(转换[顺序]中的类型t)
{
ConstructorInfo c=t.GetConstructor(新类型[]{typeof(CommandLine)});
DataConversion d=(DataConversion)c.Invoke(新对象[]{CommandLine.Instance});
ConversionVersionStatus状态=d.VersionStatus(CommandLine.Instance.TaskParameterValue(“TAX_FULL_VERSION”);
if((status==conversionstatus.noversionstatus)| |(status==conversionstatus.Relevant))
{
d、 Log(String.Format(CultureInfo.InvariantCulture,“启动转换{0}”,d.FriendlyName));
d、 ExecuteTask();
d、 日志(String.Format(CultureInfo.InvariantCulture,“已完成转换{0}”,d.FriendlyName));
}
其他的
{
如果(状态==转换版本状态已停止)
{
d、 Log(String.Format(CultureInfo.InvariantCulture,“转换{0}被跳过为中断”,d.FriendlyName));
}
其他的
{
d、 Log(String.Format(CultureInfo.InvariantCulture,“转换{0}因尚未相关而跳过”,d.FriendlyName));
}
}
}
}
}
因此,基本上要添加一个新任务,我们在dll中定义它,用该属性标记它,job done


在此之后,您将讨论某种配置文件,无论是显式配置文件,还是DI和服务发现路径。

取决于程序集的组织方式,但这里有一种方法。 定义自定义属性 调用say MyTask,这样您就可以识别感兴趣的程序集中的所有类,并且在您的示例中要公开的名称是“connect”

然后使用反射来钳制组件,找到您想要的CHAP并注册它们

不知道你对属性和r了解多少