10

この問題の最善の解決策は何ですか? null が意味のある値であり、デフォルトとして使用できないクラス型のいくつかのオプション パラメータを持つ関数を作成しようとしています。のように、

public void DoSomething(クラス 1 オプション 1、クラス 2 オプション 2、クラス 3 オプション 3)
    {
        if (! WasSpecified(optional1)) { optional1 = defaultForOptional1; }
        if (! WasSpecified(optional2)) { optional2 = defaultForOptional2; }
        if (! WasSpecified(optional3)) { optional3 = defaultForOptional3; }

        // ... 実際の作業を行います ...
    }

Class1 optional1 = nullnullは意味があるので使えません。これらのオプションのパラメーターにはコンパイル時の定数が必要なため、一部のプレースホルダー クラス インスタンスを使用できませんClass1 optional1 = defaultForOptional1。次のオプションを考え出しました。

  1. 可能なすべての組み合わせでオーバーロードを提供します。つまり、このメソッドには 8 つのオーバーロードがあります。
  2. デフォルトを使用するかどうかを示す各オプション パラメータにブール型パラメータを含めます。これにより、署名が乱雑になります。

これに対する巧妙な解決策を思いついた人はいますか?

ありがとう!

編集:のラッパークラスを作成することになったので、繰り返し続ける必要はありませんでしたBoolean HasFoo

    /// <summary>
    /// A wrapper for variables indicating whether or not the variable has
    /// been set.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public struct Setable<T>
    {
        // According to http://msdn.microsoft.com/en-us/library/aa288208%28v=vs.71%29.aspx,
        // "[s]tructs cannot contain explicit parameterless constructors" and "[s]truct
        // members are automatically initialized to their default values."  That's fine,
        // since Boolean defaults to false and usually T will be nullable.

        /// <summary>
        /// Whether or not the variable was set.
        /// </summary>
        public Boolean IsSet { get; private set; }

        /// <summary>
        /// The variable value.
        /// </summary>
        public T Value { get; private set; }

        /// <summary>
        /// Converts from Setable to T.
        /// </summary>
        /// <param name="p_setable"></param>
        /// <returns></returns>
        public static implicit operator T(Setable<T> p_setable)
        {
            return p_setable.Value;
        }

        /// <summary>
        /// Converts from T to Setable.
        /// </summary>
        /// <param name="p_tee"></param>
        /// <returns></returns>
        public static implicit operator Setable<T>(T p_tee)
        {
            return new Setable<T>
            {
                IsSet = true
              , Value = p_tee
            };
        }
    }
4

5 に答える 5

12

少なくとも、パラメーターの新しい型を作成することを検討します。

public void DoSomething(DoSomethingOptions options)

... DoSomethingOptions は次のようになります。

public class DoSomethingOptions
{
    private Class1 class1;
    public bool HasClass1 { get; private set; }

    public Class1 Class1 
    {
        get { return class1; }
        set
        {
            class1 = value;
            HasClass1 = true;
        }
    }

    ... for other properties ...
}

次に、次のように呼び出すことができます。

DoSomething(new DoSomethingOptions { Class1 = null, Class2 = new Class2() });

オーバーロードの指数関数的なセットになってしまうことはなく、それでもかなりコンパクトに呼び出すことができます。

これは、 で使用するアプローチに似ていProcessますProcessStartInfo

于 2012-05-23T20:36:57.357 に答える
7

考えられるすべての組み合わせでオーバーロードを提供します。つまり、このメソッドには 8 つのオーバーロードがあります。

これは私の好みです。これにより、状況が非常に明確になり、維持しやすくなります。内部的には、単一の初期化ルーチンにマップして、重複するコードを減らすことができます。

于 2012-05-23T20:33:59.553 に答える
6

null私は「何もない」という意味を作りstatic readonlyたいと思います。次に、意味を持たせる代わりに、本来意図されていたように null を「無」として使用できます。Class1Class2Class1Class2Nonenull

それが紛らわしい場合:

public class Class1
{
    public static readonly Class1 None = new Class1();
}
public static Class2
{
    public static readonly Class2 None = new Class2();
}

nullあなたのケースで「None」以外のもの(「MissingData」など)を意味する場合は、メンバーにそのように名前を付ける必要があることに注意してください。また、これは、将来あなたのコードを読んだり使用したりする他の人々にとってより意味のあるものになります。

于 2012-05-23T20:37:16.267 に答える
2

Flags使用するクラスをマークするために渡すことができる列挙を作成できます。

[Flags]
public enum DoSomethingOptions
{
    None = 0,
    UseClass1 = 1,
    UseClass2 = 2,
    UseClass3 = 4,
    etc..
}

DoSomething(Class1 class1, ..., DoSomethingOptions options = DoSomethingOptions.None) { ... }

次に、その列挙を渡して、使用するクラスをマークします。nullnull以外を意味していたのはなぜですか?これは解決策かもしれませんが、「設計を再考してください」と言いたいです。

于 2012-05-23T20:49:08.073 に答える
1

ええ、オブジェクトを使ってみてください。可能な選択肢をカプセル化するクラスを定義します。オブジェクトに選択肢が設定されている場合、元のプロパティのセッターを使用して設定されている場合は、同じオブジェクトに格納できます。

例:

internal class SettingsHolder
{
    public SettingsHolder()
    {
        IsOriginalPropADefault = true;
    }

    private Class1 originalProp;
    public Class1 OriginalProp
    {
        get
        {
            return originalProp;
        }
        set
        {
            originalProp = value;
            IsOriginalPropADefault = false;
        }
    }

    public bool IsOriginalPropADefault { get; private set; }

}
于 2012-05-23T20:36:36.407 に答える