passing an array without being a copy c# - c#

How can i pass an array without making a copy of it?
I have:
private readonly IList<GameObjectTemplate> mMapGameObjects;
public GameObjectTemplate[] GetObjects(GameObjectType type)
{
List<GameObjectTemplate> tempObjects = new List<GameObjectTemplate>();
for (int i = 0; i < mMapGameObjects.Count; i++)
{
if (mMapGameObjects[i].Type == type)
{
tempObjects.Add(mMapGameObjects[i]);
}
}
return tempObjects.ToArray();
}
So i want to select only my objects of a certain type and return the same array without being a copy.Is it possible?

Unless you really need an array as result consider returning IEnumerable<GameObjectTemplate>:
public IEnumerable<GameObjectTemplate> GetObjects(GameObjectType type)
{
return mMapGameObjects.Where(m => m.Type == type);
}

Related

How do I cast/convert an array of objects to generic type T when T is defined as an array?

Given a generic class Foo<T> with a method public T Convert(string value), I am trying to handle the possibility that T is defined as an array.
For example, T as a simple type:
Foo<int> foo = new Foo<int>();
int bar = foo.Convert("123");
// bar == 123
But also, T as an array:
Foo<int[]> foo = new Foo<int[]>();
int[] bars = foo.Convert("1,2,3");
// bars = [1, 2, 3]
Here is class Foo with an invalid cast that I'm not quite sure how to resolve.
public class Foo<T>
{
public T Convert(string value)
{
Type t = typeof(T);
if (t.IsArray)
{
string[] values = value.Split(',');
Type elementType = t.GetElementType();
// this cast is invalid
return (T)values.Select(v => elementType.IsEnum ? Enum.Parse(elementType, v, true) : ChangeType(v, elementType)).ToArray();
}
else
{
return (T)ChangeType(value, t);
}
}
private object ChangeType(string value, Type type)
{
if (type.IsGenericType && type.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
{
if (value == null)
{
return default;
}
type = Nullable.GetUnderlyingType(type);
}
return System.Convert.ChangeType(value, type);
}
}
You are not really using the features of generics here, except getting the type via typeof(T). So a solution without generics would be:
public class Foo
{
public object Convert(string value, Type t)
{
if (t.IsArray)
{
string[] values = value.Split(',');
Type elementType = t.GetElementType();
var array = Array.CreateInstance(elementType, values.Length);
for (var i = 0; i < values.Length; i++)
{
array.SetValue(elementType.IsEnum ? Enum.Parse(elementType, values[i], true) : ChangeType(values[i], elementType), i);
}
return array;
}
else
{
return ChangeType(value, t);
}
}
private object ChangeType(string value, Type type)
{
if (type.IsGenericType && type.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
{
if (value == null)
{
return default;
}
type = Nullable.GetUnderlyingType(type);
}
return System.Convert.ChangeType(value, type);
}
}
Note that I use Array.CreateInstance to create e.g. a proper int[] instead of the object[] created by your values.Select(v => elementType.IsEnum ? Enum.Parse(elementType, v, true) : ChangeType(v, elementType)).ToArray().
If you want, you can still have a generic version on top of it:
public class Foo<T> : Foo
{
public T Convert(string value)
{
return (T)Convert(value, typeof(T));
}
}
Why not keep your impl that understands Foo<int> and use it to make an array:
int[] bars = "1,2,3".Split(",").Select(foo.Convert).ToArray();
This way the calling method can be the one who knows how the array is arranged rather than baking it into Convert as a CSV:
int[] bars = "1-2-3".Split("-").Select(foo.Convert).ToArray();
I do wonder what you really gain over swapping foo.Convert out for int.Parse though.. Looks like you're writing a large, confusing, slow mega parser for little gain over offering a static Parse method per your custom type and calling it as per above

C# ValueTuple of any size

Is it possible to write a C# method that accepts a value tuple with any number of items of the same type and converts them into a list?
Edit 2/6/2019
I accepted the Provided answer as the correct one. I wanted to also provide a solution that uses a base class that is not an interface, becuase I am trying to write a conversion operator and user defined conversions from an interface are not allowed.
public static class TupleExtensions
{
public static IEnumerable<object> Enumerate(this ValueType tpl)
{
var ivt = tpl as ITuple;
if (ivt == null) yield break;
for (int i = 0; i < ivt.Length; i++)
{
yield return ivt[i];
}
}
}
You can use the fact that ValueTuples implement the ITuple interface.
The only issue is that tuple elements can be of arbitrary type, so the list must accept any kind of type.
public List<object> TupleToList(ITuple tuple)
{
var result = new List<object>(tuple.Length);
for (int i = 0; i < tuple.Length; i++)
{
result.Add(tuple[i]);
}
return result;
}
This also works as an extension method:
public static class ValueTupleExtensions
{
public static List<object> ToList(this ITuple tuple)
{
var result = new List<object>(tuple.Length);
for (int i = 0; i < tuple.Length; i++)
{
result.Add(tuple[i]);
}
return result;
}
}
This way it is possible to write var list = (123, "Text").ToList();.
Edit 2020-06-18: If every element of the tuple is of the same type it's possible to create list with the proper element type:
public List<T> TupleToList<T>(ITuple tuple)
{
var result = new List<T>(tuple.Length);
for (int i = 0; i < tuple.Length; i++)
{
result.Add((T)tuple[i]);
}
return result;
}

Using Indexers for multiple Arrays in the class 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;
}
}
}

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

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