我有以下C#代码。它工作正常;但GetDestination()
方法使用is operator混乱了多个if
条件。
在.Net 4.0(或更高版本)中,避免这些“if”条件的最佳方法是什么?
编辑:角色是业务模型的一部分,目标纯粹是使用该业务模型的一个特定应用程序的工件。
CODE
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();
}
}
参考
答案 0 :(得分: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();
答案 1 :(得分:5)
这是一个选项:
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";
}
注意:
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
是商业模式的一部分,目的地纯粹是人工制品使用该业务模型的一个特定应用程序在这种情况下,你不应该将它放入Role
,因为这会打破关注点的分离。
基本上,在不了解更多背景的情况下,我们无法确定哪种解决方案最合适 - 在设计方面往往是如此。
答案 2 :(得分:4)
方法1(已选中):使用dynamic
关键字实施multimethods
/ double dispatch
方法2 :使用dictionary
来避免{SAMPet'在以下答案中提到的if
个阻止。
方法3:如果条件不是相等,则使用HashList
和delegates
(例如,如果输入&lt; 25)。请参阅how to refactor a set of <= , >= if...else statements into a dictionary or something like that
Apporach 4:虚拟功能如MarcinJuraszek在下面的回答中所述。
使用动态关键字
的MultiMethods / Double Dispatch方法原理:此处算法会根据类型进行更改。也就是说,如果输入是Accountant,则要执行的功能与Manager不同。
public static class DestinationHelper
{
public static string GetDestinationSepcificImplm(Manager x)
{
return @"\ManagerHome";
}
public static string GetDestinationSepcificImplm(Accountant x)
{
return @"\AccountantHome";
}
public static string GetDestinationSepcificImplm(Cleaner x)
{
return @"\CleanerHome";
}
}
class Program
{
static string GetDestination(Role x)
{
#region Other Common Works
//Do logging
//Other Business Activities
#endregion
string destination = String.Empty;
dynamic inputRole = x;
destination = DestinationHelper.GetDestinationSepcificImplm(inputRole);
return destination;
}
static void Main(string[] args)
{
string destination = GetDestination(new Security());
Console.WriteLine(destination);
Console.WriteLine("....");
Console.ReadLine();
}
}
答案 3 :(得分:2)
这是一种强类型的命令式语言,因此if
语句和类型检查将会发生。
话虽如此,您是否考虑过virtual
上的Role
方法可以覆盖以提供目的地string
?
另一种选择,查找表!
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];
答案 4 :(得分:1)
角色应该有一个返回目标的虚函数:
public virtual string GetDestination()
{
return "Home";
}
并且所有类都应该覆盖此函数并返回正确的字符串。然后在代码中你会有:
var role = new Accountant();
string destination = role.GetDestination();
我希望有所帮助。可能有拼写错误,我正在写作。
答案 5 :(得分:1)
一种方法是使用地图而不是if:
//(psuedocode)
private Dictionary<Type, string> RoleMap;
void SomeInitializationCodeThatRunsOnce()
{
RoleMap.Add(typeof(Manager), @"\ManagerHome");
RollMap.Add(typeof(Accountant), @"\AccountantHome");
// ect...
}
string GetDestination(Role x)
{
string destination;
if(!RoleMap.TryGet(x.GetType(), out destination))
destination = @"\Home";
return destination;
}
进一步阅读:http://www.hanselman.com/blog/BackToBasicsMovingBeyondForIfAndSwitch.aspx
答案 6 :(得分:0)
您可以使用接口定义或抽象方法/属性
with interface:
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";
}