[英]How to refactor the pervasive if statement for type check
我正在使用已经使用了大约十年的旧系统,在其中定义了一种基本数据结构,如下所示:
[Serializable()]
public class DataClass
{
private Array _values;
private readonly Type _valueType;
public DataClass(Array tmpArray, Type tmpType)
{
_values = tmpArray;
_valueType = tmpType;
}
public Array GetValues()
{
return _values;
}
public Type ValueType
{
get { return _valueType; }
}
public void SetValues(Array newValues, int fromIndex)
{
// 1. type check, if _values and newValues don't share same data type, throws an exception
// 2. length check
if (fromIndex + newValues >= _values.Length)
throws new InvalidDataException();
// 3. set values
for (var i = fromIndex; i < newValues.Length; i++)
_values.SetValue(newValues.GetValue(i - fromIndex), i);
}
...blahblah
}
我相信他们的倡议是他们希望仅使用一个类来支持不同的数据类型,例如
new DataClass(new int[]{1,2,3,4}, typeof(int));
new DataClass(new float[]{1f,2f,3f,4f}, typeof(float));
现在我想给init DataClass
使用默认值,分析后,我发现,API SetValues
进行更长时间的阵列(很慢boxing
和unboxing
我相信),并使得程序不太敏感,我决定使用通用和大量的if else语句为了加快速度,例如:
void InitValues(DataClass data)
{
if (data.ValueType == typeof(int))
InitWith(data, -1);
else
if (data.ValueType == typeof(double))
InitWith(data, -9.99d);
...blahblah
}
void InitWith<T>(DataClass data, T defaultValue)
{
// much faster
var array = (T[])data.GetValues();
for (var i = 0; i < array.Length; i++)
array[i] = defaultValue;
}
但是我有很多像InitValues
这样的性能关键型方法。由于DataClass
支持的值类型DataClass
,因此编写和维护这样的代码很DataClass
。
鉴于这一事实,我没有自己的源代码, DataClass
,我不能做任何改变的DataClass
。 我想知道是否有一种重构的方法,以便可以在一个地方处理所有类型为if
语句?
鉴于您不允许更改DataClass
,我们需要使DataClass
高效。 一种方法是使用字典将类型映射到操作/方法。 我们只需要初始化一次这些字典。 这是此类的示例。
class ConsumerClass // the one which uses DataClass objects
{
// All the Mappings required by this consumer class
readonly Dictionary<Type, Action<DataClass>> InitMap = new Dictionary<Type, Action<DataClass>>();
readonly Dictionary<Type, Action<DataClass>> DoSomethingAMap = new Dictionary<Type, Action<DataClass>>();
readonly Dictionary<Type, Action<DataClass>> DoSomethingBMap = new Dictionary<Type, Action<DataClass>>();
// Constructor
public ConsumerClass()
{
// Initialize all the mappings for all the required types for this consumer class here.
// This is a one time overhead, but will definitely speedup the methods within this class
// You could move this part further up the hierarchy of inheritance, to avoid repetitions in every other consumer class.
// For int
InitMap.Add(typeof(int), data => InitWith(data, -1));
DoSomethingAMap.Add(typeof(int), DoSomethingA<int>);
DoSomethingBMap.Add(typeof(int), DoSomethingB<int>);
// For double
InitMap.Add(typeof(double), data => InitWith(data, -9.99d));
DoSomethingAMap.Add(typeof(double), DoSomethingA<double>);
DoSomethingBMap.Add(typeof(double), DoSomethingB<double>);
// other types, if needed by this consumer
}
void InitValues(DataClass data)
{
// This takes care of your if s
InitMap[data.ValueType].Invoke(data);
}
void InitWith<T>(DataClass data, T defaultValue)
{
// much faster
var array = (T[])data.GetValues();
for (var i = 0; i < array.Length; i++)
array[i] = defaultValue;
}
void DoSomethingA(DataClass data)
{
DoSomethingAMap[data.ValueType].Invoke(data);
}
void DoSomethingA<T>(DataClass data)
{
var array = (T[])data.GetValues();
// do something
}
void DoSomethingB(DataClass data)
{
DoSomethingBMap[data.ValueType].Invoke(data);
}
void DoSomethingB<T>(DataClass data)
{
var array = (T[])data.GetValues();
// do something
}
}
构造函数中有一些冗余代码,因此仍然有更好的方法来编写此机制。 但是,您应该了解如何清理ifs并仍然提高性能。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.