0

私が書いているサーバーの場合、ファイルのフォルダーがあり、各ファイルに1つのクラスがあります。
各クラスは、クライアントからの要求アクションを表します。
新しいアクションを追加する場合は、単に新しいファイルを追加して、ファイル自体を登録できるようにしたいだけです。

Goなどの言語では、初期化時に実行される関数を各ファイルに1つずつ持つことができinit、ファクトリデリゲート(またはファーストクラス関数)などを登録できます。

登録されているすべてのアクションのリストを含む2番目のファイルを編集しなくても、ファイルに独自のクラスを登録させるという、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);
        }
    }
}
4

3 に答える 3

2

アセンブリの編成方法によって異なりますが、これを行う 1 つの方法を次に示します。MyTask と呼ばれるカスタム属性を定義して、対象のアセンブリ内のすべてのクラスを識別できるようにします。公開する名前は、例では「接続」などです。

次に、リフレクションを使用してアセンブリを挟み、必要なチャップを見つけて登録します。

属性と反射についてどれだけ知っているかわかりません

しかし、これは私のものです

[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));
               }
           }
       }
   }
}

基本的に、新しいタスクを追加するには、dll で定義し、その属性でマークアップして、ジョブを完了します。

この後、明示的なものか、DI およびサービス検出ルートをたどる、ある種の構成ファイルについて話していることになります。

于 2012-12-03T13:01:07.410 に答える
1

コンソールアプリの場合は、Mainメソッドの開始時に実行してください。

Windowsサービスの場合、拡張すると、サービスの開始時に実行されるメソッド(オーバーライド可能)をServiceBase取得します。http://msdn.microsoft.com/en-us/library/system.serviceprocess.servicebase.onstart.aspxOnStart

開始するためのWindowsサービスに関する簡単なチュートリアルは次のとおりです。http ://www.switchonthecode.com/tutorials/creating-a-simple-windows-service-in-csharp

編集:あなたの説明に基づいて、AFAIK、ファイル/タイプにあなたが求めていることをさせる組み込みの方法はありません。しかし、あなたができることは、いくらかの反省です。を実装する特定のタイプ/インターフェースIAction(または、他の記述型)についてアセンブリを熟読することができます。それらすべてを検索してインスタンス化し、init上記の起動フェーズでさまざまなメソッドを呼び出すことができます。

于 2012-12-03T12:30:07.750 に答える
1

クラスで静的初期化子を使用できます。

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);
        }
    }
}
于 2012-12-03T12:41:35.217 に答える