我正在使用已有大约十年的遗留系统,其中一个基本数据结构定义如下:
[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));
现在我想使用默认值初始化DataClass
,在分析后我发现API SetValues
对于较长的数组(boxing
和unboxing
而言相当慢)并且使程序响应性降低,我决定使用 Generic 和许多 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
进行任何更改。我想知道是否有一种方法可以重构,以便我可以在一个地方中处理所有类型检查的if
语句?
答案 0 :(得分:2)
鉴于您不允许更改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并仍然提高性能。