我有一个看起来像这样的课:
public class Grid<T>
{
public T[] gridArray;
public Grid(int size)
{
gridArray = new T[size];
gridArray.FillArray<T>();
}
}
我希望我的gridArray.FillArray<T>();
方法用gridArray
填充-1
(如果类型为int
,并用false
填充,如果类型为bool
。
我该如何实现?
答案 0 :(得分:1)
好像您想为此创建扩展方法。一种选择是使用重载,并为所需的每种类型实现单独的方法
public static class Ext
{
public static void FillArray(this int[] array)
{
for (int i = 0; i < array.Length; i++)
{
array[i] = -1;
}
}
public static void FillArray(this bool[] array)
{
for (int i = 0; i < array.Length; i++)
{
array[i] = false;
}
}
}
当您显式创建int
或bool
数组时,可以使用这种方法
var arr = new int[size];
arr.FillArray();
并且不可能像在Grid
中那样对通用参数使用此方法。因此,另一种选择是创建带有运行时检查类型的通用扩展方法
public static class Ext
{
public static void FillArray<T>(this T[] array)
{
Type itemType = typeof(T);
T value;
if (itemType == typeof(bool))
{
value = (T)Convert.ChangeType(false, itemType);
}
else if (itemType == typeof(int))
{
value = (T)Convert.ChangeType(-1, itemType);
}
else
{
value = default(T);
}
for (int i = 0; i < array.Length; i++)
{
array[i] = value;
}
}
}
注意
请考虑以下事实:实例化数组(new type[size]
)时,该数组已经被其类型的默认值填充(0
为int
,{{1}为{{ 1}})。因此,如果默认值适合您,则可能不需要这些扩展方法。
答案 1 :(得分:1)
在这个问题上我可以看到两个问题
除了手动创建之外,没有一种干净的方法可以用自定义默认值填充通用数组。
您可能也想阅读这个StackOverflow问题,因为它与本主题相关:
What is the equivalent of memset in C#?
考虑到这一点,您可以将Grid
类定义如下:
public class Grid<T>
{
private T[] _gridArray;
public Grid(int size)
{
_gridArray = new T[size];
}
public Grid(int size, T initialValue)
{
_gridArray = new T[size];
for (int i = 0; i < size; i++)
_gridArray[i] = initialValue;
// or it can be rewritten with LINQ, if you like:
// _gridArray = Enumerable.Repeat(initialValue, size).ToArray();
}
}
现在,您可以使用它来创建默认数组:
var grid = new Grid<int>(3); // [0, 0, 0]
var grid = new Grid<object>(3); // [null, null, null]
var grid = new Grid<bool>(4); // [false, false, false, false]
,但是您还可以提供一个默认值:
var grid = new Grid<int>(3, -1); // [-1, -1, -1]
var grid = new Grid<bool>(4, true); // [true, true, true, true]
如果您希望-1
是 all Grid<int>
的默认值,则可以创建一个工厂,工厂将对此进行了解并根据此逻辑进行创建。该工厂可以存储每种类型的默认值,并根据它们验证您的T
。
当然,您可以将此逻辑放入构造函数中,就像您最初希望的那样:
public class Grid<T>
{
private static readonly Dictionary<Type, object> _customDefaultValues = new Dictionary<Type, object>
{
[typeof(int)] = -1,
[typeof(long)] = long.MaxValue
};
public T[] _gridArray;
public Grid(int size)
{
_gridArray = new T[size];
if (_customDefaultValues.TryGetValue(typeof(T), out object defaultValue))
{
T defaultValueUnboxed = (T)defaultValue;
for (int i = 0; i < size; i++)
_gridArray[i] = defaultValueUnboxed;
}
}
}
var grid = new Grid<int>(4); // [-1, -1, -1, -1]
var grid = new Grid<long>(2); // [long.MaxValue, long.MaxValue]
var grid = new Grid<bool>(3); // [false, false, false]
但是对我来说,它看起来有点草率且不透明。此外,它为每个创建封闭的泛型类型创建静态_customDefaultValues
的新实例。这就是为什么最好将其提取为工厂类。
public class Grid<T>
{
private T[] _gridArray;
public Grid(int size)
{
_gridArray = new T[size];
}
public Grid(int size, T initialValue)
{
_gridArray = new T[size];
for (int i = 0; i < size; i++)
_gridArray[i] = initialValue;
}
}
public static class GridFactory
{
private static readonly Dictionary<Type, object> _customDefaultValues = new Dictionary<Type, object>
{
[typeof(int)] = -1,
[typeof(long)] = long.MaxValue
};
public static Grid<T> Create<T>(int size)
{
if (_customDefaultValues.TryGetValue(typeof(T), out object defaultValue))
return new Grid<T>(size, (T)defaultValue);
return new Grid<T>(size);
}
}
它产生了更多的代码,但是这样看起来更加清晰:
var grid = GridFactory.Create<int>(3); // [-1, -1, -1]
var grid = GridFactory.Create<long>(4); // [long.MaxValue, long.MaxValue, long.MaxValue, long.MaxValue]
var grid = GridFactory.Create<object>(3); // [null, null, null] by default