3

次のC#コードがあります。正常に動作します。しかし、メソッドはis 演算子を使用することで複数の条件GetDestination()で雑然としています。if

.Net 4.0 (またはそれ以降) では、これらの「if」条件を回避する最善の方法は何ですか?

編集: ロールはビジネス モデルの一部であり、宛先は純粋にそのビジネス モデルを使用する特定のアプリケーションの成果物です。

コード

public class Role { }
public class Manager : Role { }
public class Accountant : Role { }
public class Attender : Role { }
public class Cleaner : Role { }
public class Security : Role { }

class Program
{
    static string GetDestination(Role x)
    {
        string destination = @"\Home";

        if (x is Manager)
        {
            destination = @"\ManagerHomeA";
        }

        if (x is Accountant)
        {
            destination = @"\AccountantHomeC";
        }

        if (x is Cleaner)
        {
            destination = @"\Cleaner";
        }

        return destination;

    }

    static void Main(string[] args)
    {
        string destination = GetDestination(new Accountant());
        Console.WriteLine(destination);
        Console.ReadLine();
    }
}

参考文献

  1. さまざまなタイプのデリゲートを持つ Dictionary<T,Delegate>: よりクリーンな非文字列メソッド名?
  2. Jon Skeet: リフレクションを飛ばしてデリゲートを探る
  3. if-else vs. スイッチ vs. デリゲートの辞書
  4. デリゲートまたはスイッチを使用した辞書?
  5. C# での式とデリゲート
4

7 に答える 7

5

1 つのオプションを次に示します。

private static readonly Dictionary<Type, string> DestinationsByType =
    new Dictionary<Type, string> 
{
    { typeof(Manager), @"\ManagerHome" },
    { typeof(Accountant), @"\AccountantHome" },
    // etc
};

private static string GetDestination(Role x)
{
    string destination;
    return DestinationsByType.TryGetValue(x.GetType(), out destination)
        ? destination : @"\Home";
}

ノート:

  • これは null パラメータには対応していません。実際にそれが必要かどうかは明らかではありません。ただし、null 処理を簡単に追加できます。
  • これは継承ではコピーされません (例: class Foo : Manager)。必要に応じて継承階層を上ることでそれを行うことができます

複雑さを犠牲にして、これらの両方のポイントを処理するバージョンを次に示します。

private static string GetDestination(Role x)
{
    Type type = x == null ? null : x.GetType();
    while (type != null)
    {
        string destination;
        if (DestinationsByType.TryGetValue(x.GetType(), out destination))
        {
            return destination;
        }
        type = type.BaseType;
    }
    return @"\Home";
}

Role編集:それ自体がプロパティを持っていれば、よりきれいになりDestinationます。これは仮想であるか、Role基本クラスによって提供されます。

ただし、宛先は実際にはRoleそれ自体に関係するものではない可能性があります。それRoleはビジネス モデルの一部である可能性があり、宛先は純粋にそのビジネス モデルを使用する 1 つの特定のアプリケーションの成果物である可能性があります。そのような状況では、関心の分離を壊すので、それを に入れるべきではありません。Role

基本的に、より多くのコンテキストを知らなければ、どのソリューションが最も適しているかを判断することはできません。これは、デザインの問題でよくあることです。

于 2014-01-21T15:02:09.513 に答える
5

virtual派生クラスでオーバーライドされるプロパティを持つことで、トリックを行う必要があります。

class Role
{
    public virtual string Destination { get { return "Home"; } }
}
class Manager : Role
{
    public override string Destination { get { return "ManagerHome;"; } }
}
class Accountant : Role
{
    public override string Destination { get { return "AccountantHome;"; } }
}
class Attender : Role
{
    public override string Destination { get { return "AttenderHome;"; } }
}
class Cleaner : Role
{
    public override string Destination { get { return "CleanerHome;"; } }
}
class Security : Role { }

Home派生クラスでオーバーライドされていない場合にデフォルト値を提供するために、プロパティを抽象化しませんでした。

使用法:

string destination = (new Accountant()).Destination;
Console.WriteLine(destination);
Console.ReadLine();
于 2014-01-21T15:00:00.993 に答える
2

これは強く型付けされた命令型言語であるため、ifステートメントと型チェックが行われます。

そうは言っても、宛先を提供するためにオーバーライドできるvirtualメソッドを検討しましたか?Rolestring

さらに別の方法として、ルックアップ テーブルがあります。

Dictionary<Type, string> paths = new Dictionary<TYpe, string>()
{
    { typeof(Manager),  @"\ManagerHomeA" }
    { typeof(Accountant),  @"\AccountantHomeC" }
    { typeof(Cleaner),  "Cleaner" }
}

string path = @"\Home";
if(paths.ContainsKey(x.GetType())
    path = paths[x];
于 2014-01-21T14:57:57.093 に答える
1

ロールには、宛先を返す仮想関数が必要です。

public virtual string GetDestination()
{
     return "Home";
}

そして、すべてのクラスがこの関数をオーバーライドして、正しい文字列を返す必要があります。次に、コードで次のようになります。

var role = new Accountant();
string destination = role.GetDestination();

それが役立つことを願っています。頭から書いているので誤字脱字があるかもしれません。

于 2014-01-21T14:59:13.983 に答える
0

インターフェイス定義または抽象メソッド/プロパティのいずれかを使用できます

インターフェイス付き:

public interface IDestinationProvider
{
    sting Destination { get; }
}

string GetDestination(Role role)
{
    var provider = role as IDestinationProvider;
    if (provider != null)
        return provider.Destination;
    return "Default";
}

抽象基本クラスで

abstract class Role 
{ 
    public abstract string GetDestination();
}

class Manager : Role
{
    public virtual string GetDestination() { return "ManagerHomeA"; }
}

string GetDestination(Role role)
{
    return @"\" + role.GetDestination();
}

または属性付き:

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class DestinationAttribute : Attribute
{
    public DestinationAttribute() { this.Path = @"\Home"; }
    public string Path { get; set; }
}

[Destination(Path = @"\ManagerHome")]
public class Manager : Role { }

string GetDestination(Role role)
{
    var destination = role.GetType().GetCustomAttributes(typeof(DestinationAttribute), true).FirstOrDefault();
    if (destination != null)
        return destination.Path;

    return @"\Home";
}
于 2014-01-21T15:01:48.847 に答える