3

私が取り組んでいるプロジェクトでは、他の複数のサイトで使用される 1 つの DLL を作成する必要があります。この DLL 内で、約 10 個の Enum を参照する必要があります。ただし、これらの Enum の値は、DLL が使用されるサイトごとに異なります。例えば:

MyBase.dll には、MyEnum 型の属性を持つクラス MyClass がある場合があります。

次に、MyBase.dll が MySite で参照されます。MyStie は、MyEnum 型の値を含む MyEnums.dll も参照します。

これを達成する方法はありますか?MyBase.dll をビルドしているときに、MyEnums.dll の側にどの列挙型が存在するかを知っています。問題は、MyBase.dll が特定のプロジェクトで使用されるまで作成されない MyEnums.dll を具体的に参照しないと、MyBase.dll をビルドできないことです。

それが理にかなっており、ここで答えが見つかることを願っています。

ありがとう。

編集:

すべてのコメントをありがとう。完全に理解するには数回読む必要がありますが、ここで私が見ているもののより良い例を挙げてみましょう.

次のコードが、さまざまなプロジェクトに配置される私の DLL にあるとしましょう。ステータスは列挙型です。

public Class MyClass
{
    private Status _currentStatus;

    public Status CurrentStatus
    {
        get
        {
            return _currentStatus;
        }
    }

    public void ChangeStatus(Status newStatus)
    {
        _currentStatus = newStatus;
    }
}

私ができるようにしたいのは、個々のプロジェクトでステータスの可能な値を定義することです。したがって、この DLL では、Status 列挙に含まれる可能性のある値を参照することは決してありません。それが存在することを知っていればよいだけです。

私がやろうとしていることについて、もう少し明確になることを願っています。

4

2 に答える 2

2

各クライアントに (異なるアセンブリ バージョンで) 異なる列挙値を表示させたい場合、列挙型を使用するのは悪い解決策です。変更するとクライアント コードが壊れます...

列挙型の使用は機能する可能性があります (列挙型名とアセンブリ名が同じで、アセンブリが署名されていない限り) - アセンブリを交換するだけです。ただし、最後に存在しないコードのどこかで値が使用されている場合は、例外が発生します。また、値の異なるサブセットが異なる値に対して同じ番号になったり、同じ値に対して異なる番号になったりしないように、明示的に値に番号を付けることができます。

代わりに、リスト、辞書、データベース テーブルなど、動的に構築されたコレクションの使用を検討してください。または、列挙値の同じスーパーセットを持つ同じアセンブリをすべての人に提供し、ユーザーに関連する値を決定させます (おそらく、慣習として値に重要なプレフィックスを使用します)。

または、2つの組み合わせを使用できます...

サイトごとに異なる構造 (異なる型名 (または名前空間) とアセンブリ名) を (サイトのプロファイルに従って) 異なるプロパティで生成し、構造を受け入れるサービスの 1 つのマスター構造を生成します。すべての構造体に同じインターフェイスを実装してもらいます。これを受け取ると予想されます...

public interface IStatus
{
    string GetKey();
}

public struct ClientXStatus : IStatus
{
    private readonly string _key;

    private ClientXStatus(string key)
    {
        _key = key;
    }

    // Don't forget default for structs is 0,
    // therefore all structs should have a "0" property.
    public ClientXStatus Default
    {
        get
        {
            return new ClientXStatus();
        }
    }

    public ClientXStatus OptionB
    {
        get
        {
            return new ClientXStatus(10);
        }
    }

    string IStatus.GetKey()
    {
        return _key;
    }

    public override bool Equals(object obj)
    {
        return (obj is IStatus) && ((IStatus)obj).GetKey() == _key;
    }

    public override int GetHashCode()
    {
        return _key.GetHashCode();
    }

    public static bool operator==(ClientXStatus x, IStatus y)
    {
        return x.Equals(y);
    }

    public static bool operator==(IStatus x, ClientXStatus y)
    {
        return y.Equals(x);
    }

    public static bool operator!=(ClientXStatus x, IStatus y)
    {
        return !x.Equals(y);
    }

    public static bool operator!=(IStatus x, ClientXStatus y)
    {
        return !y.Equals(x);
    }

    // Override Equals(), GetHashCode() and operators ==, !=
    // So clients can compare structures to each other (to interface)
}

サービスのマスター構造体を使用します。

public struct MasterStatus : IStatus
{
    private readonly string _key;

    private MasterStatus(string key)
    {
        _key = key;
    }

    // Don't forget default for structs is 0,
    // therefore all structs should have a "0" property.
    public MasterStatus Default
    {
        get
        {
            return new MasterStatus();
        }
    }

    // You should have all the options here
    public MasterStatus OptionB
    {
        get
        {
            return new MasterStatus(10);
        }
    }

    // Here use implicit interface implementation instead of explicit implementation
    public string GetKey()
    {
        return _key;
    }

    public static implicit operator MasterStatus(IStatus value)
    {
        return new MasterStatus(value.GetKey());
    }

    public static implicit operator string(MasterStatus value)
    {
        return new value._key;
    }

    // Don't forget to implement Equals, GetHashCode,
    // == and != like in the client structures
}

デモ サービス コード:

public void ServiceMethod(IStatus status)
{
    switch (status.GetKey())
    {
        case (string)MasterStructA.OptionB:
            DoSomething();
    }
}

または:

public void ChangeStatus(IStatus status)
{
    _status = (MasterStatus)status;
}

このようにして:

  1. コード生成を使用して、値の衝突を防ぎます。

  2. 値を (非公開として) 非表示にし、構造体のみを受け入れることにより、ユーザーにコンパイル時チェック (int 値または文字列値なし) を使用するように強制します。

  3. エラーが発生しやすいハックではなく、サービスのコード (インターフェイス) で実際のポリモーフィズムを使用します。

  4. 参照型ではなく、不変の値型 (列挙型など) を使用します。

于 2012-06-07T21:18:12.847 に答える
0

まず、定数を配置する場所を決定する必要があります。enum次に、静的プロパティに変換できます。

例えば:

public enum MyEnum
{
    Value1,
    Value2
}

(最初の単純なアプローチ) に変更できます。

public static class MyFakeEnum
{
    public static int Value1
    {
        get { return GetActualValue("Value1"); }
    }

    public static int Value2
    {
        get { return GetActualValue("Value2"); }
    }

    private static int GetActualValue(string name)
    {
        // Put here the code to read the actual value
        // from your favorite source. It can be a database, a configuration
        // file, the registry or whatever else. Consider to cache the result.
    }
}

これは単に必要な定数を提供するだけですが、パラメーターとして必要な場合は、型のコンパイル時のチェックを破棄する必要がありMyFakeEnumます。より良い解決策については、たとえば、Microsoft が (多かれ少なかれ) に対して行ったことに従うことができますSystem.Drawing.Color

public sealed class MyFakeEnum
{
    public static readonly MyFakeEnum Value1 = new MyFakeEnum("Value1");
    public static readonly MyFakeEnum Value2 = new MyFakeEnum("Value2");

    private MyFakeEnum(string name)
    {
        _name = name;
    }

    public static implicit operator int(MyFakeEnum value)
    {
        return GetActualValue(value._name);
    }

    private string _name;
}

もちろん、少なくとも 、EqualsGetHashCodeおよびには適切なオーバーライドを提供する必要がありToStringます。

プロ

  • これは、既存の からのアップグレードである可能性がありますenum。コードが壊れることはなく、再コンパイルする必要があるかもしれません。
  • 厳密に型指定されたパラメーターとして使用できます。例:void DoSomething(MyFakeEnum value)は有効であり、呼び出し元は他のものを渡すことができません (列挙型は弱いと見なされるため、これが理由の 1 つに注意してください)。
  • 必要な演算子をすべて実装すると、比較に通常の構文を使用できますvalue == MyFakeEnum::Value1
  • 少しのコードで、FlagsAttribute構文を実装することさえできます。
  • enums: の通常の構文は変更しませんMyFakeEnum.Value1
  • 型との間で任意の数の暗黙的/明示的な変換演算子を実装できます。変換は安全であり、完了した時点でチェックされます (これは、標準の列挙型には当てはまりません)。
  • 変更によって破損する可能性があり、実行時エラーが発生するまでキャッチされないハードコーディングされた文字列はありません (はい、実行時)。たとえば、辞書を使用して定義を変更すると、すべてのコードでその文字列を検索する必要があります。

短所

  • サポートコードを記述する必要があるため、最初の実装は長くなります (ただし、新しい値については、新しい行を追加するだけです)。
  • 値リストは固定されており、コンパイル時に認識されている必要があります (これも固定されているため、の代替を検索している場合は問題になりませenumん)。

このソリューションを使用すると、標準の列挙型とほぼ同じ構文を保存できます。

于 2012-06-07T21:20:48.200 に答える