2

プラグインをサポートする C# でアプリケーションを作成しています。アプリケーションが適切な環境を準備できるように、各プラグインは自己紹介する必要があります。現在の情報オブジェクトは、次のようには見えません。

class FilterInfo
{
    public InputInfo[] inputs; 
    public OutputInfo[] outputs;
    bool IsConfigurable;
    bool IsPlayable;
    string TypeName;
}

この構造は、今後確実に拡大していくでしょう (とはいえ、それほど大きくはないと思いますが、おそらくそのサイズは 2 倍になるでしょう)。私は現在、そのような情報クラスを適切に実装する方法を考えています。

C++ では、次のようにします (例を読みやすくするために、クラスを 1 つのフィールドに取り除きます)。

class FilterInfo
{
private:
    std::vector<const InputInfo> inputs;

public:
    std::vector<const InputInfo> & GetInputs()
    {
        return inputs;
    }

    const std::vector<const InputInfo> & GetInputs() const
    {
        return inputs;
    }
}

現在、プラグインはFilterInfoクラスをインスタンス化し、そのフィールドに入力してから、要求に応じて戻りconst FilterInfo、誰も情報の内容を変更できないようにします (そうすべきではありません)。

C# では、次の「安全な」ソリューションしか想像できません。

public interface IInputInfo
{
    bool SomeData
    {
        get;
    }       
}

public class InputInfo : IInputInfo
{
    private bool someData;

    public bool SomeData
    {
        get
        {
            return someData;
        }
        set
        {
            someData = value;
        }
    }

    public bool IInputInfo.SomeData
    {
        get
        {
            return someData;
        }
    }
}

public interface IFilterInfo
{
    ReadOnlyCollection<IInputInfo> Inputs
    {
        get;
    }
}

public class FilterInfo : IFilterInfo
{
    private InputInfo[] inputs;

    public InputInfo[] Inputs
    {
        get
        {
            return inputs;
        }
        set
        {
            inputs = value;
        }
    }

    public ReadOnlyCollection<IInputInfo> IFilterInfo.Inputs
    {
        return inputs;
    }
}

もちろん、プラグインはIFilterInfo代わりに を返しFilterInfo、データが読み取り専用になるようにします (OK、リフレクションについては知っています。問題は、データを変更してはならないことをユーザーに通知することです)。ただし、このソリューションは非常に不器用に見えます。特に、先ほど引用したコンパクト バージョンと比較した場合はなおさらです。

別の解決策として、getter のみを使用して FilterInfo を作成することもできますが、何らかの方法でデータを渡す必要があり、多くのパラメーターを持つ巨大なコンストラクターになる可能性があります。


編集:別の解決策は、構造体を作成し、リクエストごとにそのコピーを返すことです。ただし、配列は参照によってコピーされるため、毎回手動でコピーする必要があります。

さらに別の方法は、誰かが要求するたびに FilterInfo を最初から構築することです。

public FilterInfo Info
{
    get
    {
        return new FilterInfo()
            {
                IsConfigurable = true,          
                IsPlayable = false,
                Inputs = new[]
                    {
                        new InputInfo()
                            {
                            // (...)
                            }
                    }
            }
    }
}

この問題を解決するエレガントな方法はありますか?

4

3 に答える 3

0

セッターをプライベートまたは保護に設定するのはどうですか。

public class FilterInfo
{
    public InputInfo[] inputs { get; private set; } 
    public OutputInfo[] outputs { get; private set; };
    bool IsConfigurable;
    bool IsPlayable;
    string TypeName;

    public void SetInputs(...)
    {
        InputInfo[] allInputs;
        //do stuff
        inputs = AllInput;
    }

    public void SetOutputs(...)
    {
        OutputInfo[] allOutputs;
        //do stuff
        outputs = AllOutput;
    }
}

内部メソッドを使用してデータを設定したり、保護したりして、継承を通じてオブジェクトを変更できるようにすることができます。

UPDATE セッターに内部アクセサーを使用するのはどうですか。この方法では、FilterInfo を含むアセンブリで定義される InternalsVisibleTo アセンブリ レベル属性で宣言されない限り、セッターにアクセスできません。

次の投稿では、 internal キーワードを使用してこれを行う方法について説明しています。 内部説明

アップデート

別の解決策として、getter のみを使用して FilterInfo を作成することもできますが、何らかの方法でデータを渡す必要があり、多くのパラメーターを持つ巨大なコンストラクターになる可能性があります。

this によると、ゲッターがないことの唯一の問題は、データを渡す必要があることです。元のソリューションでは、これが可能です。ちょっと戸惑うこともあるかと思います。プラグインが参照によってこの API の情報を変更できる場合、私は推測しています。次に、アプリケーションが同じアセンブリを参照している場合、プラグインにも同じアクセサーが提供されます。セッターを内部に設定し、属性を介したアクセスを許可する以外に、そのタイプの機能を実現する唯一の方法があるようです。ただし、API を参照しているアセンブリがわからないため、これはうまくいきません。

于 2013-04-09T05:49:27.533 に答える