根据类型,用默认值填充T []

时间:2019-03-08 21:18:31

标签: c# arrays

我有一个看起来像这样的课:

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

我该如何实现?

2 个答案:

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

当您显式创建intbool数组时,可以使用这种方法

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])时,该数组已经被其类型的默认值填充(0int,{{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]

如何根据通用T设置自定义默认值

如果您希望-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