我想优化此代码以减少if
语句的数量。也许最好使用很多类,让这些类处理每个必需的操作?
可能是织物图案吗?还是可以使用30多个类似的if
语句?
我尝试使用Dictionary
和string
类制作一个object
。但是我无法使它工作(或者我的技能不够好)
if (node[DATA_CONNECTION_ELEMENT] != null)
{
return new DataConnectionPropertyDataBinding(form, node[DATA_CONNECTION_ELEMENT], inputableEntity);
}
else if (node[FORM_PARAMETER_ELEMENT] != null)
{
return new FormParameterDataBinding(form, node[FORM_PARAMETER_ELEMENT], inputableEntity);
}
// + 30 more else ifs
else if (node[COMMAND_ELEMENT] != null)
{
return new CommandResultDataBinding(form, node[COMMAND_ELEMENT], inputableEntity);
}
else if (node[CONDITION_ELEMENT] != null)
{
return new ConditionDataBinding(form, node[CONDITION_ELEMENT], inputableEntity);
}
else if (node[CLIPBOARD_ELEMENT] != null)
{
return new ClipboardDataBinding(form, node[CLIPBOARD_ELEMENT], inputableEntity);
}
else
{
return new ConstantDataBinding(form, node);
}
想要使其看起来像
foreach (var item in allThatShareSomeInterface)
{
if (item.CanHandle(node.Atributes[0]))
{
return item.neededObject();
}
}
这是答案。它是如何工作的。
Dictionary<string, Type> allObjects = new Dictionary<string, Type>();
allObjects.Add(CONDITION_ELEMENT, typeof(ConditionDataBinding));
allObjects.Add(DATA_TYPE_FORMAT_ELEMENT, typeof(DataTypeFormatDataBinding));
allObjects.Add(DATA_TYPE_CONVERT_ELEMENT, typeof(DataTypeConvertDataBinding));
allObjects.Add(FORM_PARAMETER_ELEMENT, typeof(FormParameterDataBinding));
allObjects.Add(FORM_ELEMENT, typeof(FormPropertyDataBinding));
allObjects.Add(STRING_ELEMENT, typeof(StringFormatDataBinding));
allObjects.Add(FORMULA_ELEMENT, typeof(FormulaDataBinding));
allObjects.Add(COMMAND_ELEMENT, typeof(CommandResultDataBinding));
// + many
foreach (var pair in allObjects)
{
if (node[pair.Key] != null)
{
ConstructorInfo ctor = pair.Value.GetConstructor(new[] { typeof(IWorkflowForm), typeof(XmlNode), typeof(IInputable) });
return ctor.Invoke(new object[] { form, node[pair.Key], inputableEntity });
}
}
答案 0 :(得分:1)
您也许可以使用反射进行这项工作。不过,这可能会使您的代码慢一些。 它应该看起来像这样(未经测试):
var pairs = new Dictionary<string, Type>()
{
{
DATA_CONNECTION_ELEMENT, typeof(DataConnectionPropertyDataBinding)
},
{
FORM_PARAMETER_ELEMENT, typeof(FormParameterDataBinding)
}
};
foreach (var pair in pairs)
{
if (node[pair.Key] != null)
{
ConstructorInfo ctor = pair.Value.GetConstructor(new[] { typeof(object), typeof(object), typeof(object) });
return ctor.Invoke(new object[] { form, node[pair.Key], inputableEntity });
}
}
答案 1 :(得分:0)
如果您知道自己在做什么,并且确实需要那么多的绑定类,解决此问题的一种方法是自定义属性+反射+运行时代码生成。这是一个例子。
// Enum for element type. The order matters, it's the order in which input dictionary is tested.
enum eElement
{
DataConnection,
FormParameter,
}
// Custom attribute to mark bindings classes with.
class DataBindingAttribute : Attribute
{
public eElement element;
public DataBindingAttribute( eElement e ) { element = e; }
}
// Base class for bindings
abstract class BindingBase { }
// Couple test binding classes
[DataBinding( eElement.DataConnection )]
class DataConnectionPropertyDataBinding: BindingBase
{
public DataConnectionPropertyDataBinding( object data ) { }
}
[DataBinding( eElement.FormParameter )]
class FormParameterDataBinding: BindingBase
{
public readonly object data;
public FormParameterDataBinding( object data ) { this.data = data; }
}
// This static class does the magic.
static class BindingsFactory
{
// Key = eElement from custom attribute, value = function that constructs the binding. This example uses the constructor with single object argument.
// It's a good idea to use strong types for arguments instead.
static readonly SortedDictionary<eElement, Func<object, BindingBase>> dictTypes = new SortedDictionary<eElement, Func<object, BindingBase>>();
static BindingsFactory()
{
// Constructor argument types, just a single `object` in this example.
Type[] constructorArgumentTypes = new Type[ 1 ]
{
typeof( object )
};
ParameterExpression[] constructorArgumentExpressions = constructorArgumentTypes
.Select( tp => Expression.Parameter( tp ) )
.ToArray();
// Find all types in current assembly
var ass = Assembly.GetExecutingAssembly();
foreach( Type tp in ass.GetTypes() )
{
// Try to get the custom attribute
var dba = tp.GetCustomAttribute<DataBindingAttribute>();
if( null == dba )
continue;
// Ensure you don't have 2 classes with the same element ID value
Debug.Assert( !dictTypes.ContainsKey( dba.element ) );
// Ensure the found type inherits from BindingBase
Debug.Assert( typeof( BindingBase ).IsAssignableFrom( tp ) );
// Compile the function that constructs the new binding object
ConstructorInfo ci = tp.GetConstructor( constructorArgumentTypes );
Debug.Assert( null != ci );
// new Binding(...)
var expNew = Expression.New( ci, constructorArgumentExpressions );
// (BindingBase)( new Binding( ... ) )
var expCast = Expression.Convert( expNew, typeof( BindingBase ) );
// Compile into lambda
var lambda = Expression.Lambda<Func<object, BindingBase>>( expCast, constructorArgumentExpressions );
// Compile the lambda, and save in the sorted dictionary
var func = lambda.Compile();
dictTypes.Add( dba.element, func );
}
}
public static BindingBase tryConstruct( Dictionary<eElement, object> dict )
{
foreach( var kvp in dictTypes )
{
object arg;
if( !dict.TryGetValue( kvp.Key, out arg ) )
continue;
return kvp.Value( arg );
}
return null;
}
}
class Program
{
static void Main( string[] args )
{
var dict = new Dictionary<eElement, object>();
dict[ eElement.FormParameter ] = 12;
// This line will construct an instance of FormParameterDataBinding
var res = BindingsFactory.tryConstruct( dict );
}
}