使用许多“ if”语句优化代码

时间:2019-05-29 13:24:27

标签: c# if-statement

我想优化此代码以减少if语句的数量。也许最好使用很多类,让这些类处理每个必需的操作?

可能是织物图案吗?还是可以使用30多个类似的if语句?

我尝试使用Dictionarystring类制作一个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 });
            }
        }

2 个答案:

答案 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 );
    }
}