5

プラグイン ベースのシステムに似たデスクトップ アプリケーションを開発しています。「マシン」オブジェクトを含む DLL をロードするクライアント モジュールがあります。その後、「Machine」オブジェクトは、適切に定義されたインターフェイスに従って操作および使用されます。

注意が必要なのは、'Machine' オブジェクトを含む DLL が、別のプログラムを使用してオンザフライで生成されることです。核となる DLL 生成アプリケーションは、ユーザー入力を受け取り、クラスを C# コード ファイル (ユーザーが指定したフィールドを含みますが、私は事前に知りません) で生成し、それらのクラスを DLL (machine. dll ファイル)。

クライアント プログラムは、この dll を取得し、動的にロードして、このマシン オブジェクトで動作します。

Machine オブジェクトと Client プログラムの間でデータを受け渡す問題に対処するためのソリューションをモデル化する際に、多くの問題に直面しています。これは、基本的に Machine オブジェクトに含まれるデータがわからないためです。

クライアントプログラムは、次のことを行います。

-- dll をロードし、「マシン」オブジェクトをインスタンス化します。-- インターフェイスを介してクライアントに認識されている「マシン」オブジェクトの一連の関数を呼び出します。-- 「マシン」オブジェクトからさまざまな変数を抽出し、ユーザーに表示します。

最後のステップを実行できません。

注:フィールドに関するメタデータがdll生成プログラムによって生成され、xmlファイルに保存される簡単なソリューションをプログラムしました。クライアント プログラムは、これらの xml ファイルを使用して、マシン オブジェクトに格納されているフィールドに関する情報を取得します。次に、マシン オブジェクトのリフレクションを使用して、オブジェクトのフィールドにアクセスします。

これは面倒で遅いと思います。この種のパターンや方法はありますか??

4

2 に答える 2

3

これを読んで頭に浮かんだ解決策は、C#の組み込みの属性サポートを利用することでした。属性は、プロパティ、フィールド、メソッド、クラスなどに追加のメタデータをタグ付けする方法であり、その後、たとえばSerialization中に他のクラスによって使用されます。あなたはそこでそれを最も頻繁に見るでしょう。

IEnumerableオブジェクトのコレクションを取得し、ユーザーが選択した選択に基づいてファイルにデータを出力できるようにする必要があるアプリケーションを構築していました。リフレクションを介して選択肢を読み取り、指示どおりに動作できるようにする属性クラスを作成しました。例を示しましょう。

最初の属性クラス:

[System.AttributeUsage(AttributeTargets.Property)]
class ExportOptionsAttribute : System.Attribute
{
    public string Header { get; set; }
    public string FormatString { get; set; }
    public bool Export { get; set; }
    public int Order { get; set; }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="header"></param>
    public ExportOptionsAttribute(string header) : this (header, null, true)
    {

    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="header"></param>
    /// <param name="formatString"></param>
    /// <param name="export"></param>
    public ExportOptionsAttribute(string header, string formatString, bool export)
    {
        this.Header = header;
        this.FormatString = formatString;
        this.Export = export;
        this.Order = 0;
    }
}

このクラスをこのように定義すると、データ クラスのプロパティを次のように装飾できます (実際のプロパティは、ビジネス用語で迷子にならないように変更されています)。

public sealed class PartsOrder
{
    /// <summary>
    /// 
    /// </summary>  
    [ExportOptions("Customer Name", Order=0)]
    public string CustomerName { get; set; }

    /// <summary>
    /// 
    /// </summary>
    [ExportOptions("Catalog Name", Order = 1)]
    public string Catalog Name { get; set; }

    /// <summary>
    /// 
    /// </summary>
    [ExportOptions("Unit", Order = 2)]
    public string Unit { get; set; }

    /// <summary>
    /// 
    /// </summary>
    [ExportOptions("Component", Order = 3)]
    public string Component { get; set; }

    /// <summary>
    /// 
    /// </summary>
    [ExportOptions("Delivery Point", Order = 4)]
    public string DeliveryPoint { get; set; }

    /// <summary>
    /// 
    /// </summary>  
    [ExportOptions("Order Date", Order = 5)]
    public string OrderDate { get; set; }
}

そのため、エクスポート ルーチンでは、変数であるプロパティ名をハードコーディングしたり、表示または非表示にするフィールドや順序に関する情報を含む複雑なデータ構造を渡したりする代わりに、次のコードを実行しました。 、リフレクションを使用して、プロパティをループし、その値を CSV ファイルに出力します。

StringBuilder outputDoc = new StringBuilder();

// loop through the headers in the attributes
// a struct which decomposes the information gleaned from the attributes
List<OrderedProperties> orderedProperties = new List<OrderedProperties>();

// get the properties for my object
PropertyInfo[] props =
    (typeof(PartsOrder)).GetProperties();

// loop the properties
foreach (PropertyInfo prop in props)
{
    // check for a custom attribute
    if (prop.GetCustomAttributesData().Count() > 0)
    {
        foreach (object o in prop.GetCustomAttributes(false))
        {
            ExportOptionsAttribute exoa = o as ExportOptionsAttribute;

            if (exoa != null)
            {
                orderedProperties.Add(new OrderedProperties() { OrderByValue = exoa.Order, PropertyName = prop.Name, Header = exoa.Header, Export = exoa.Export });
            }
        }
    }
}

orderedProperties = orderedProperties.Where(op => op.Export == true).OrderBy(op => op.OrderByValue).ThenBy(op => op.PropertyName).ToList();

foreach (var a in orderedProperties)
{
    outputDoc.AppendFormat("{0},", a.Header);
}

// remove the trailing commma and append a new line
outputDoc.Remove(outputDoc.Length - 1, 1);
outputDoc.AppendFormat("\n");


var PartsOrderType = typeof(PartsOrder);

//TODO: loop rows
foreach (PartsOrder price in this.Orders)
{
    foreach (OrderedProperties op in orderedProperties)
    {
        // invokes the property on the object without knowing the name of the property
        outputDoc.AppendFormat("{0},", PartsOrderType.InvokeMember(op.PropertyName, BindingFlags.GetProperty, null, price, null));
    }

    // remove the trailing comma and append a new line
    outputDoc.Remove(outputDoc.Length - 1, 1);
    outputDoc.AppendFormat("\n");
}

OrderedProperties 構造体のコードは次のとおりです。

struct OrderedProperties
{
    /// <summary>
    /// 
    /// </summary>
    public int OrderByValue;
    /// <summary>
    /// 
    /// </summary>
    public string PropertyName;
    /// <summary>
    /// 
    /// </summary>
    public string Header;
    /// <summary>
    /// 
    /// </summary>
    public bool Export;
}

ご覧のとおり、プロパティ値を抽出するロジックは、クラスの構造をまったく認識していません。作成した属性で修飾されたプロパティを見つけて、それを使用して処理を実行するだけです。

これがすべて意味をなすことを願っています。さらにヘルプや説明が必要な場合は、お気軽にお問い合わせください。

于 2012-12-14T05:09:40.320 に答える
2

また、アプリケーション間の通信を可能にする軽量の MQ ソフトウェアである ZeroMQ をピックアップすることもできます。ZeroMQ には 1 つの dll のみが含まれており、任意のアプリケーションに組み込むことができます。

ZeroMQ には、C、C++、.NET、Python、Java、Ruby など、あらゆる種類のクライアントがあり、Windows/Linux/OSX の両方で実行できます。

于 2012-12-14T04:42:04.833 に答える