Using Indexers for multiple Arrays in the class c# - c#

I have two arrays in my Base class, and I want to create Indexers that can be used in both of them, attached below is an MVCE of what I am trying to do.
class Indexer
{
private string[] namelist = new string[size];
private char[] grades = new string[size];
static public int size = 10;
public IndexedNames() {
for (int i = 0; i < size; i++){
namelist[i] = "N. A.";
grades[i] = 'F';
}
}
public string this[int index] {
get {
string tmp;
if( index >= 0 && index <= size-1 ) {
tmp = namelist[index];
} else {
tmp = "";
}
return ( tmp );
}
set {
if( index >= 0 && index <= size-1 ) {
namelist[index] = value;
}
}
}
In the above coed if you comment out the lines private char[] grades = new string[size]; and grades[i] = 'F'; then you can use the indexers as object_name[i] but I want to be able to access both namelist and grades by indexers.
Note : I cannot use structures to wrap them together as in my application, there size may not always be same.
Is this possible or I would need to go around with some hack.
Edit
I am looking for something like names.namelist[i] and names.grades[i], or some statements that I can access them separately. Also Indexer logic is not consistent, and even size varies in some arrays, that was skipped here to aid simplicity in MVCE.

Sorry, no-can-do.
Although Indexers can be Overloaded and can have more than one formal parameter, you can't make two variations based on the same Parameter in the same class. This is a Language Limitation (or blessing).
Indexers (C# Programming Guide)
However, this should lead you to several options.
You can just make use of C#7. Ref returns
Starting with C# 7.0, C# supports reference return values (ref
returns). A reference return value allows a method to return a
reference to a variable, rather than a value, back to a caller. The
caller can then choose to treat the returned variable as if it were
returned by value or by reference. The caller can create a new
variable that is itself a reference to the returned value, called a
ref local.
public ref string Namelist(int position)
{
if (array == null)
throw new ArgumentNullException(nameof(array));
if (position < 0 || position >= array.Length)
throw new ArgumentOutOfRangeException(nameof(position));
return ref array[position];
}
...
// Which allows you to do funky things like this, etc.
object.NameList(1) = "bob";
You could make sub/nested classes with indexers
That's to say, you could create a class that has the features you need with indexers, and make them properties of the main class. So you get something like you envisaged object.Namelist[0] and object.Grades[0].
Note : in this situation you could pass the arrays down as references and still access them in the main array like you do.
Example which includes both:
Given
public class GenericIndexer<T>
{
private T[] _array;
public GenericIndexer(T[] array)
{
_array = array;
}
public T this[int i]
{
get => _array[i];
set => _array[i] = value;
}
}
Class
public class Bobo
{
private int[] _ints = { 2, 3, 4, 5, 5 };
private string[] _strings = { "asd","asdd","sdf" };
public Bobo()
{
Strings = new GenericIndexer<string>(_strings);
Ints = new GenericIndexer<int>(_ints);
}
public GenericIndexer<string> Strings ;
public GenericIndexer<int> Ints ;
public void Test()
{
_ints[0] = 234;
}
public ref int DoInts(int pos) => ref _ints[pos];
public ref string DoStrings(int pos) => ref _strings[pos];
}
Usage:
var bobo = new Bobo();
bobo.Ints[1] = 234;
bobo.DoInts(1) = 42;

I think only a two parameter indexer can achieve what you want.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace ConsoleApp1
{
class MyClass
{
protected static Dictionary<string, FieldInfo[]> table = new Dictionary<string, FieldInfo[]>();
static public int size = 10;
protected char[] grades = new char[size];
public object this[string name, int index]
{
get
{
var fieldInfos = table[this.GetType().FullName];
return ((Array)fieldInfos.First((x) => x.Name == name).GetValue(this)).GetValue(index);
}
set
{
var fieldInfos = table[this.GetType().FullName];
((Array)fieldInfos.First((x) => x.Name == name).GetValue(this)).SetValue(value, index);
}
}
static void Main()
{
var names = new MyChildClass();
names[DataColumns.Grades, 1] = 'S';
names[DataColumns.NameList, 9] = "W.S";
}
}
class MyChildClass : MyClass
{
private string[] namelist = new string[size];
static MyChildClass()
{
var t = typeof(MyChildClass);
table.Add(t.FullName, t.GetFields(BindingFlags.NonPublic | BindingFlags.Instance));
}
public MyChildClass()
{
for (int i = 0; i < size; i++)
{
namelist[i] = "N. A.";
grades[i] = 'F';
}
}
}
static class DataColumns
{
public static string NameList = "namelist";
public static string Grades = "grades";
}
}

Maybe something like this:
class Indexer
{
private string[] namelist = new string[size];
private string[] grades = new string[size + 1]; // size +1 to indicate different
// size
static public int size = 10;
public void IndexedNames()
{
for (int i = 0; i < size; i++)
{
namelist[i] = "N. A.";
grades[i] = "F";
}
}
public string this[int i, int j]
{
get
{
string tmp;
// we need to return first array
if (i > 0)
{
tmp = namelist[i];
}
else
{
tmp = grades[i];
}
return (tmp);
}
set
{
if (i > 0)
{
namelist[i] = value;
}
else grades[i] = value;
}
}
}

Related

How do I approach array properties when I need an array to have an interval in C#?

I am extremely new to C# and am still trying to wrap my head around some of its core concepts.First time posting a question to StackOverflow.
So this is what I need help with:
Make a property for: private string array; : so that:
"Each element of an array needs to be >=0 and <=10"
Should I run it through for, and then set array=value for each element or what?
This is what I did:
private string array;
public int[] Array
{
get { return array; } //-is this part good for the task?
set
{
//what do I do here to make sure the elements are withing the
//given interval?
}
}
See if this is what you need (Demo):
public class myClass
{
private int[] _Array = new int[10];
public int this[int index]
{
get { return _Array[index]; }
set
{
if (value >= 0 && value <= 10)
_Array[index] = value;
}
}
}
public class Program
{
public static void Main(string[] args)
{
myClass m = new myClass();
m[0] = 1;
m[1] = 12;
Console.WriteLine(m[0]); // outputs 1
Console.WriteLine(m[1]); // outputs default value 0
}
}
You are looking for something like this
private int[] _privateArray;
public int[] PublicArray
{
get
{
return _privateArray;
}
set
{
foreach (int val in value)
{
if (val < 0 || val > 10) throw new ArgumentOutOfRangeException();
}
// if you get to here you can set value
_privateArray = (int[])value.Clone();
}
}
please note private property and public property must be same type

Fill T[] with default value depending on type

I have a class which looks like this:
public class Grid<T>
{
public T[] gridArray;
public Grid(int size)
{
gridArray = new T[size];
gridArray.FillArray<T>();
}
}
I'd like my gridArray.FillArray<T>(); method to fill the gridArray with -1, if it's of type int and to fill it with false, if it's of type bool.
How can i achieve this?
I can see two concerns in this question
How to create an array with non-default prefilled values?
There is no clean way to fill a generic array with custom default value, except for creating it manually.
You might want to read this StackOverflow question too, because it is related to this topic:
What is the equivalent of memset in C#?
Taking this into account, you can define your Grid class as the following:
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();
}
}
Now, you can use it to create default arrays:
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]
but you can also provide a value which you would like to be as a default:
var grid = new Grid<int>(3, -1); // [-1, -1, -1]
var grid = new Grid<bool>(4, true); // [true, true, true, true]
How to set custom default values per generic T
If you want -1 to be default value for all Grid<int>, you can create a factory, which will know about it and create this according to this logic. This factory can store default values for each type and validate your T against them.
Of course, you could put this logic into constructor just like you initially wanted it to be:
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]
but for me it looks a little bit sloppy and non-transparent. Also, it creates new instance of static _customDefaultValues for each create closed generic type. That's why it would be better to extract it to a factory class.
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);
}
}
It results into more code, but this way it looks more clear:
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
Looks like you want to create an extension method for this. One option is to use overloading and implement separate method for every type you need
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;
}
}
}
It's possible to use this approach when you explicitely create int or bool array
var arr = new int[size];
arr.FillArray();
And it is not possible to use this approach with generic parameter like you do in Grid. So another option would be creating generic extension method with checking type in runtime
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;
}
}
}
Note
Consider the fact that when you instantiate an array (new type[size]) it is already filled by default value of its type (0 for int and false for bool). So possibly you won't need these extension method if default values are okay for you.

Array index return null instead of out of bound

I am currently trying to implement an "indexed" property within my class definition.
For example I have the following class:
public class TestClass
{
private int[] ids = null;
public string Name { get; set; }
public string Description { get; set; }
public int[] Ids {
get
{
//Do some magic and return an array of ints
//(count = 5 - in this example in real its not fixed)
return _ids;
}
}
}
Now I like to use this class as the following:
private void DoSomething()
{
var testClass = GetSomeTestClass();
//work with the ids
for (int i = 0; i < 10; i++) //I know I could say i < Ids.Length, its just an example
{
int? id = testClass.Ids[i];
//this will result, in a out of bound exception when i reaches 5 but I wish for it to return a null like a "safe" index call ?!?
}
}
So is there a safe index call that results in a null, without the need for me to wrap it again and again in a try catch.
Another thing I dont wish to use the class index, because I need several properties that work like this, with different types (int, string, bool, custom class and so on).
(Again the for is just a simple example, I know I could in this case say "i < Ids.Length")
If you were only interested in already non-nullable type data e.g. struct you could have gotten away with a simple extension method e.g.
public static class ArrayExt
{
public static Nullable<T> GetValueOrNull(this T[] array, int index) where T: struct
{
return array.Length < index ? new Nullable<T>(array[index]) : null;
}
}
which would have allowed you to simply call
int? id = testClass.Ids.GetValueOrNull(i);
However, given you need to support an arbitrary number of types my suggestion would be to implement a wrapper around an array and take control over how you access the data e.g.
public class SafeArray<T>
{
private T[] items;
public SafeArray(int capacity)
{
items = new T[capacity];
}
public object this[int index]
{
get
{
return index < items.Length ? (object)items[index] : null;
}
set
{
items[index] = (T)value;
}
}
}
public class TestClass
{
public TestClass()
{
Ids = new SafeArray<int>(5);
Instances = new SafeArray<MyClass>(5);
}
...
public SafeArray<int> Ids { get; private set; }
public SafeArray<MyClass> Instances { get; private set; }
}
The key to this approach is to use object as the return type. This allows you to cast (or box/unbox if using value types) the data to the expected type on the receiving end e.g.
for (int i = 0; i < 10; i++)
{
// we need an explicit cast to un-box value types
var id = (int?)testClass.Ids[i];
// any class is already of type object so we don't need a cast
// however, if we want to cast to original type we can use explicit variable declarations e.g.
MyClass instance = testClass.Instances[i];
}
OK, whole new approach. Since you have several possible types and want a "joker" method, you can store the values as key/value collection in your class then such method becomes possible.
First, to store the values internally:
public class TestClass
{
private Dictionary<Type, Array> _values = new Dictionary<Type, Array>();
}
Now to populate that collection with actual data:
_values.Add(typeof(int?), new int[] { 1, 2, 3 });
_values.Add(typeof(string), new string[] { "a", "b", "c", "d", "e" });
And finally the joker method:
public T Get<T>(int index)
{
Type type = typeof(T);
Array array;
if (_values.TryGetValue(type, out array))
{
if (index >= 0 && index < array.Length)
{
return (T)array.GetValue(index);
}
}
return default(T);
}
Usage:
for (int i = 0; i < 10; i++)
{
int? id = testClass.Get<int?>(i);
string name = testClass.Get<string>(i);
//...
}
There's really not much else you can do here than just:
if (i >= array.Length) return null;
else return array[i];
or, using the ? operator:
return (i >= array.Length) ? null : array[i];
You could use method instead of property:
public int? Ids(int i) {
if (i >= 0 && i < _ids.length)
{
return _ids[i];
}
return null;
}
from what I have read I see you are implemet a property of an array type, but not an indexer
it is kind of a moveton to fake index out of range situation and it would be still much much better if you take in your code care about out of range. at the end of the day nobody prevent you on assigning a default (in your case NULL) value when range is violated
if you need a shortcut for your the situation you have described above, I would go for the following method in your class:
public int? ReadAtOrNull(int index)
{
return index < ids.Lenght && index > 0 ? (int?)ids[index] : null;
}
People may start complaining that this may be an overhead, but what if you used Skip and FirstOrDefault?
for (int i = 0; i < 10; i++) //I know I could say i < Ids.Length, its just an example
{
int? id = testClass.Ids.Skip(i).FirstOrDefault();
}
Mind you that in this case you may need to declare your array as int?[] otherwise the default value is 0 instead of null.
please Try :
for (int i = 0; i < Ids.Length; i++)
{
if (!String.IsNullOrEmpty(testClass.Ids[i].Tostring())
int? id = testClass.Ids[i];
}
It seems like the think to do here is to use a class index. Here is a direct answer for your TestClass example.
You could also derive your own custom collection class strictly for Ids that stores an int[] internally and overrides all the appropriate access calls I.e) Add, Remove, etc.. (and index the collection like this to make using it easier). Then you could have a property named Ids in your TestClass that behaves like the example.
I know this question is 3 months old but I hope this still helps.
public class TestClass {
private int[] ids = new int[] { 1, 2, 3, 4, 5 };
public string Name { get; set; }
public string Description { get; set; }
public int? this[int index] {
get {
if (index < 0 || index > ids.Length - 1)
return null;
return ids[index];
}
set {
if (value == null)
throw new ArgumentNullException(
"this[index]",
"Ids are not nullable"
);
ids[index] = (int)value;
}
}
}
Usage:
private void DoSomething() {
TestClass testClass = new TestClass();
for (int i = 0; i < 10; i++) {
int? id = testClass[i];
}
// You can assign to the Ids as well
testClass[0] = 6;
}

C# - Nestable, bounded arrays

I'm porting a game written in Pascal (compiled in 16 bit) to C# (so it will run on machines newer than XP). From what I've gathered, in Pascal, it's possible to type define in the type section of a unit/program through syntax like this:
type
BaseArrayPtr = ^BaseArray;
BaseArray = array [1 .. 5, 1 .. 5] of Integer;
SubArray = array [0 .. 3] of BaseArray;
I also gathered that, unfortunately, it is impossible to type define in C#. However, I'm trying for a workaround. So far, this is what I have:
BoundedArray.cs:
using System;
using System.Collections;
namespace test
{
abstract class BoundedArray<T>
{
public BoundedArray()
{
m_data = null;
}
public T this[params int[] index]
{
get
{
if (index.Length != m_data.Rank)
throw new IndexOutOfRangeException();
return (T) m_data.GetValue(index);
}
set
{
if (index.Length != m_data.Rank)
throw new IndexOutOfRangeException();
m_data.SetValue(value, index);
}
}
protected void SetAttributes(int[] lowerBounds, int[] lengths)
{
if (lengths.Length != lowerBounds.Length)
throw new ArgumentException();
m_lowerBounds = lowerBounds;
m_lengths = lengths;
m_data = Array.CreateInstance(typeof(T), m_lengths, m_lowerBounds);
m_data.Initialize(); // Should (but doesn't) initialize every element in m_data
}
Array m_data;
int[] m_lengths;
int[] m_lowerBounds;
}
}
test.cs:
using System;
namespace test
{
class Program
{
public static int[] ints(params int[] values)
{
return values;
}
class BaseArray : BoundedArray<int>
{
public BaseArray()
{
SetAttributes(ints(2, 2), ints(1, 2));
}
}
class SubArray : BoundedArray<BaseArray>
{
public SubArray()
{
SetAttributes(ints(4), ints(2));
}
}
static void Main(string[] args)
{
SubArray subArray = new SubArray();
Console.Read();
}
}
}
I've checked baseArray, and the default values of m_data are zeroes, since they are ints. However, in subArray, the default values of m_data are null - the BaseArray instances inside the array in subArray haven't been initialized for some reason. How do I get the default constructor to run?
EDIT: The real question at the moment is why doesn't m_data.Initialize(); in the SetAttributes method initialize all elements in m_data? The documentation on MSDN seems to indicate that it should...
EDIT:
So I believe that problem is that System.Array.Initialize only works on value-types. Since classes are references types in C#, System.Array.Initialize doesn't do anything. So I have to find a way to initialize a reference-type array of variable dimensions, lengths, and lower bounds.
Well I have done some changes that when you want to create an instance of a SubArray you should pass BaseArray as source of data to be initialize.
As i understood you want to set the values from BaseArray to SubArray.
Here is my work:
BoundedArray.cs
abstract class BoundedArray<T>
{
public BoundedArray()
{
m_data = null;
}
public int[] Lengths;
public int[] LowerBounds;
public void CreateInstance()
{
if (Lengths.Length != LowerBounds.Length)
throw new Exception("Incorrect number of lengths or lower bounds.");
m_data = Array.CreateInstance(typeof(T), Lengths, LowerBounds);
}
public void CreateInstance(Array source)
{
if (Lengths.Length != LowerBounds.Length)
throw new Exception("Incorrect number of lengths or lower bounds.");
m_data = Array.CreateInstance(typeof(T), Lengths, LowerBounds);
/************************************************************************/
/* Now you should find the value of BaseArray and set it to m_data */
/************************************************************************/
}
public T this[params int[] index]
{
get
{
if (index.Length != m_data.Rank)
throw new IndexOutOfRangeException();
return (T)m_data.GetValue(index);
}
set
{
if (index.Length != m_data.Rank)
throw new IndexOutOfRangeException();
m_data.SetValue(value, index);
}
}
public Array GetData()
{
return m_data;
}
Array m_data;
}
Test.cs
class Program
{
public static int[] ints(params int[] values)
{
return values;
}
class BaseArray : BoundedArray<int>
{
public BaseArray()
{
Lengths = ints(1, 2);
LowerBounds = ints(2, 2);
CreateInstance();
}
}
class SubArray : BoundedArray<BaseArray>
{
public SubArray(BaseArray arr)
{
Lengths = ints(2);
LowerBounds = ints(4);
CreateInstance(arr.GetData());
}
}
static void Main(string[] args)
{
BaseArray baseArray = new BaseArray();
SubArray subArray = new SubArray(baseArray);
Console.Read();
}
}
You have a singe-dimensional array SubArray which holds BaseArray objects which are two-dimensional arrays of intergers. In place of Pascal type, you can define a custom C# class which would override the indexer operator to give you exactly the same behavior.
EDITED
So, in Pascal you have this:
type
BaseArrayPtr = ^BaseArray;
BaseArray = array [1 .. 5, 1 .. 5] of Integer;
SubArray = array [0 .. 3] of BaseArray;
Maybe I misunderstood the question, but is the below not exactly the same, in C#?
public class BaseArray
{
int[,] m_array = new int[5, 5];
static void CheckBounds(int x, int y)
{
if (x < 1 || x > 5 || y < 1 || y > 5)
throw new IndexOutOfRangeException();
}
public int this[int x, int y]
{
get
{
CheckBounds(x, y);
return m_array[x-1, y-1];
}
set
{
CheckBounds(x, y);
m_array[x-1, y-1] = value;
}
}
}
public class SubArray
{
BaseArray[] m_array = new BaseArray[4];
public BaseArray this[int x]
{
get { return m_array[x]; }
set { m_array[x] = value; }
}
}
I've already answered my own question once, but I came up with a much better implementation of my answer.
Here's what this solution consists of:
SetAttributes must be run once, in the default constructor of a class based off of BoundedArray
During SetAttributes, I gather a jagged, two-dimensional array of all of the indices in the current BoundedArray subclass
I create instances of the template type by calling Activator.CreateInstance and assigning one per index
Other things to note:
Set attributes now takes a variable length array of int[]s instead of two int[]s. Previously, it was taking the lowerbounds and the lengths, but I realized it makes more sense to just take int[]s which are lower and upper bounds, and then use a LINQ query to check that there aren't any which aren't pairs
I created a static class called IntArray, which is used extensively by SetAttributes and in test.cs
I tried to throw as many useful errors as possible, since I'll probably end up using this code a lot
I have a feeling that Combinations(int[][] list1, int[] list2) is probably where the most improvement on my solution could be found. I'm open to suggestions on how to improve all of my code
So, without further ado, my complete solution:
BoundedArray.cs
using System;
using System.Linq;
using System.Collections.Generic;
namespace test
{
static class IntArray
{
public static int[] FromValues(params int[] values)
{
return values;
}
public static int[] Sequence(int from, int length)
{
if (from < 0 || length < 1)
throw new ArgumentException();
return Enumerable.Range(from, length).ToArray();
}
public static int[][] Combinations(int[] list1, int[] list2)
{
return Combinations(list1.Select(i => new int[] { i }).ToArray(), list2);
}
public static int[][] Combinations(int[][] list1, int[] list2)
{
List<List<int>> result = new List<List<int>>();
for (int i = 0; i < list1.Length; i++)
{
for (int j = 0; j < list2.Length; j++)
result.Add(((int[]) list1.GetValue(i)).Concat(new int[] { list2[j] }).ToList());
}
return result.Select(i => i.ToArray()).ToArray();
}
}
abstract class BoundedArray<T>
{
public BoundedArray()
{
m_data = null;
}
public Array Value
{
get { return m_data; }
}
public T this[params int[] index]
{
get
{
if (index.Length != m_data.Rank)
throw new IndexOutOfRangeException();
return (T) m_data.GetValue(index);
}
set
{
if (index.Length != m_data.Rank)
throw new IndexOutOfRangeException();
m_data.SetValue(value, index);
}
}
protected void SetAttributes(params int[][] values)
{
// Make sure all of the values are pairs
if (values.Where(i => i.Length != 2).ToArray().Length > 0)
throw new ArgumentException("Input arrays must be of length 2.");
int[] lowerBounds = values.Select(i => i[0]).ToArray();
int[] lengths = values.Select(i => i[1] - i[0] + 1).ToArray();
m_data = Array.CreateInstance(typeof(T), lengths, lowerBounds);
int[][] indices = (lowerBounds.Length != 1) ?
IntArray.Combinations(IntArray.Sequence(lowerBounds[0], lengths[0]), IntArray.Sequence(lowerBounds[1], lengths[1]))
: IntArray.Sequence(lowerBounds[0], lengths[0]).Select(i => new int[] { i }).ToArray();
for (int i = 2; i < lowerBounds.Length; i++)
indices = IntArray.Combinations(indices, IntArray.Sequence(lowerBounds[i], lengths[i]));
for (int i = 0; i < indices.Length; i++)
m_data.SetValue(Activator.CreateInstance(typeof(T)), indices[i]);
}
Array m_data;
}
}
test.cs
using System;
namespace test
{
class Program
{
// *** Examples of what you can do with BoundedArray ***
// Multi-dimensional, bounded base array
class BaseArray : BoundedArray<int>
{
public BaseArray()
{
SetAttributes(IntArray.FromValues(2, 3), IntArray.FromValues(2, 4));
}
}
// One-dimensional, bounded subclass array
class SubArray : BoundedArray<BaseArray>
{
public SubArray()
{
SetAttributes(IntArray.FromValues(4, 6));
}
}
static void Main(string[] args)
{
// Initializations used for testing purposes
BaseArray baseArray = new BaseArray();
SubArray subArray = new SubArray();
// Example of assignment
baseArray[3, 4] = 3;
subArray[4][2, 3] = 4;
subArray[4][2] = 3; // Weakness: compiles, but causes IndexOutOfRangeException
Console.Read();
}
}
}
Thougts?

Remove an item from generic Array C#

I have a generic class defined like this
class MyGenericClass<T> where T : ICompareable
{
T[] data;
public AddData(T[] values)
{
data = values;
}
}
In mainForm, I create 3 random numbers, and add them as values, lets say 1, 2 and 3. So my T[] data; will look like this: [0]1 [1]2 [2]3
What I want to do is to remove 1 of these values from the array, how do I do that when I'm using generics. Lets say I want to remove 3 from the array so it would look like this[0]1 [1]2
Why don't you use a generic List (List<T>) instead of the array as a private member of your class to hold the data ?
As it is a private member, the 'outside world' cannot access the list, and you will have a much easier life since a List allows you to Add and Remove items easily.
class MyGenericClass<T> where T : ICompareable
{
private List<T> data = new List<T>();
public AddData(params T[] values)
{
data.AddRange (values);
}
public RemoveData( T value )
{
data.Remove (value);
}
public RemoveData( params T[] values )
{
for( int i = 0; i < values.Length; i++ )
{
data.Remove (values[i]);
}
}
}
Once you've done this, you can use the Add member-method of the List to add items, and the Remove member method to remove items. Simple as that.
I've used the params keyword in the AddData method so that you can do this:
var x = new MyGenericClass<int>();
x.AddData(1);
x.AddData(2, 3, 4);
x.AddData(somIntegerList.ToArray());
Change your class to look like this (I also implemented Frederik's suggestion of using a List instead of a array.
class MyGenericClass<T> where T : ICompareable
{
List<T> data;
public AddData(T value)
{
data.Add(value);
}
public RemoveData(T value)
{
data.Remove(value);
}
}
If for some reasaon, you insist on using an array, the remove method may look something like this
public RemoveData(T value)
{
data = data.Where( e => e.CompareTo(value) != 0).ToArray();
}
I kind of had the same question, because I was writing a dynamically sized array to practice creating generic classes.
I found that you can either: move all of the elements down and then set the last element equal to default(T), or create a new array of size-1 to be filled with the remaining elements.
Ex:
public class Array<T>
{
private T[] _array { get; set; }
private int _max { get; set; }
private int _size { get; set; }
public Array()
{
_max = 10;
_array = new T[_max];
_size = 0;
}
public T Remove(int i)
{
if (i >= _size || i < 0) return default(T);
var tmp = _array[i];
for (var j = i; j < _size-1; ++j)
{
_array[j] = _array[j + 1];
}
_array[_size - 1] = default(T);
_size--;
return tmp;
}
}
Or...
public T Remove(int i) {
var tmp = new T[_size-1];
for(var j=0; j < i; ++j)
{
tmp[j] = _array[j];
}
var result = _array[i];
for(var j=i+1; j < _size-1; ++j)
{
tmp[j] = _array[j];
}
_array = null;
_array = tmp;
return result;
}

Categories