Generics and Types and Arrays - c#

Can a 'generic type' be an array?
And in the cases where it is, how can one access that array?
Can you access a given generic type T as an array, when it is one, and as a non-array when it is not one?
For instance:
If I had a method like ->
void MustBeOfType<T>(T value){}
Can I have ->
MustBeOfType<int>(10);
And Also ->
MustBeOfType<int[]>( new int[] { 1, 2, 3 } );
And within those generic methods, can they access the values as one would expect? - one as an int and one as an int[]?
I think there might be something with typeof(T).IsArray()... but I just can't for the life of me figure out how to cast the parameter as an array when it is one.
Thanks!

You could...but, I'm not sure you should:
void MustBeOfType<T>(T value)
{
Array array = value as Array;
if (array != null) //It is an array
{
foreach (var arrayItem in array)
{
}
for (int i = 0; i < array.Length; i++)
{
var arrayItem = array.GetValue(i);
}
}
else //It is not an array
{
}
}

I am not sure what you are trying to do but Generic types can be anything. You can put restrictions to your generic type with where clause, but this is up to you and up to functionality and context.
Lets take List as example. Let say that we have List inside List. Then we define it as:
List<List<string>> myListOfList = new List<List<string>>();
your must be of type can also be anything ( if you didnt put restriction with where clause)
MustBeOfType<int[][]>()
MustBeOfType<List<List<string>>>()
MustBeOfType<AnyOtherGenericClass<List<string>>>()
and to be able to access it:
class MustBeOfType<T>
{
private T _value;
MustBeofType(T value)
{
_value = value;
}
}
to be able to make operation on , you can use reflection or if you put where restriction and your where restriction has Type, then you can see properties of that Type.

Related

return tuple with two arrays

I am trying to call a function which returns a tuple with two arrays. The content of the arrays are based on checked items in a checkedListBox.
I define the arrays and call the function "storeParametersInArrays" as shown below.
string[] allowedObjects = new string[checkedListObjects.CheckedItems.Count]; // All allowed objects
string[] notallowedObjects = new string[checkedListObjects.Items.Count - checkedListObjects.CheckedItems.Count]; // All not allowed objects
Tuple<string[], string[]> ObjParameters = storeParametersInArrays(notallowedObjects, allowedObjects, checkedListObjects);
allowedObjects = ObjParameters.Item1;
notallowedObjects = ObjParameters.Item2;
The function called is defined as:
private Tuple<string[], string[]> storeParametersInArrays(string[] notallowed, string[] allowed, CheckedListBox checkedListBox)
{
int i = 0; // allowed objects
int j = 0; // not allowed objects
int k = 0; // item counter
foreach (object item in checkedListBox.Items)
{
if (!checkedListBox.CheckedItems.Contains(item))
{
notallowed[j++] = checkedListBox.Items[k].ToString();
}
else
{
allowed[i++] = checkedListBox.Items[k].ToString();
}
k++;
}
return Tuple.Create<allowed, notallowed>;
}
I am unable to return the Tuple in the above code sample. I get the error "Cannot convert method group 'Create' to non-delegate type 'Tuple'".
It is my first time working with tuples, how can I return the two arrays without having to call the function twice?
I have looked at slightly similar problems, so if the question is already answered somewhere else, I will be glad to be pointed in the right direction.
Just change
return Tuple.Create<allowed, notallowed>;
to
return Tuple.Create(allowed, notallowed);
The first syntax is for generics: <
The second for method calls: (
You have to correct your method call Tuple.Create:
private Tuple<string[], string[]> storeParametersInArrays(string[] notallowed, string[] allowed, CheckedListBox checkedListBox)
{
int i = 0; // allowed objects
int j = 0; // not allowed objects
int k = 0; // item counter
foreach (object item in checkedListBox.Items)
{
if (!checkedListBox.CheckedItems.Contains(item))
{
notallowed[j++] = checkedListBox.Items[k].ToString();
}
else
{
allowed[i++] = checkedListBox.Items[k].ToString();
}
k++;
}
return Tuple.Create(allowed, notallowed);
}
This line
return Tuple.Create<allowed, notallowed>;
replace with
return Tuple.Create<string[], string[]>(allowed, notallowed);
Or simple
return Tuple.Create(allowed, notallowed);
The static method Create is a generic method and the error is that you are using the values like the types that the Create method will return.
You placed the values where the type parameters should be. But I think that the type parameters can be inferred here:
return Tuple.Create(allowed, notallowed);
However, you could use new ValueTuples. A simplified tuple syntax was introduced in C# 7.0.
private (string[], string[]) storeParametersInArrays(
string[] notallowed, string[] allowed, CheckedListBox checkedListBox)
{
...
return (allowed, notallowed);
}
You can then get the result stored directly into your existing variables with:
(allowedObjects, notallowedObjects) = storeParametersInArrays(
notallowedObjects, allowedObjects, checkedListObjects);
But since arrays are reference types, you don't even have to return them from the method. You are not passing copies of the arrays to the method - only references. Therefore the method fills the original arrays.
private void storeParametersInArrays(
string[] notallowed, string[] allowed, CheckedListBox checkedListBox)
{
// Fill the arrays here.
// No need for a return statement.
}
Now you can write
storeParametersInArrays(notallowedObjects, allowedObjects, checkedListObjects);
// allowedObjects and notallowedObjects are now filled. Example
string firstAllowed = allowedObjects[0];
You can even go a step further and use the Local functions introduced in C# 7.0. They have access to the variables of the surrounding method and therefore don't require the parameters in this case.
void myButton_Click(object sender, RoutedEventArgs e)
{
string[] allowedObjects = new string[...];
string[] notallowedObjects = new string[...];
storeParametersInArrays();
// Use the result
string firstAllowed = allowedObjects[0];
// Nested local function
void storeParametersInArrays()
{
// You can access allowedObjects, notallowedObjects and checkedListObjects here.
// Fill the arrays.
}
}

Creating multiple generic types (tuples) with different parameters

So suppose that I have an list called "arr." I want to move all of the contents from the list into an AVLTree that takes a tuple as the key of its (key, value) pair. I do not know how big the tuple will be before runtime (1-tuple, 2-tuple, 3-tuple, etc.); this is determined by the length of the String[] "keyOrder".
I was thinking of trying to use Type to generate the different generic types and then using Activator to instantiate a tuple from one of those types. If that is the right way to do it, how would one do it efficiently? If there's a better way to do do it, then could someone please enlighten me?
private List<IQueryable> arr { get; }
private AVLTree<IComparable, int> avlTree;
private String[] keyOrder;
public ListTable(List<IQueryable> arr, String[] keyOrder) {
this.arr = arr;
this.keyOrder = keyOrder;
}
private void createAVLTree() {
for(int i = 0; i < rows.Count; ++i) {
avlTree.Insert(/*some 1-tuple, 2-tuple, 3-tuple, etc. definition*/, i);
}
}

Automatic unboxing

I have an array of objects (object[]). All the items in this array have the same type (unknown at compile time). I need to convert this array in a typed array, that is, if the items are integers, I want to get an int[].
I've looked into the Array.ConvertAll method, but I need to specify a specific type in the template, meaning that I have to get the element type then call ConvertAll for each case possible.
I've also looked into the keyword dynamic with no more luck (looks like dynamic[] is the same as object[]).
How can I achieve this?
It sounds like you want something like:
dynamic array = Array.CreateInstance(input[0].GetType(), input.Length);
for (int i = 0; i < input.Length; i++)
{
array[i] = (dynamic) input[i];
}
Here the dynamic just handles the conversion part for you.
Alternatively:
public static Array ConvertArray(object[] input)
{
dynamic sample = input[0]; // Just used for type inference
return ConvertArrayImpl(sample, input);
}
private static T[] ConvertArrayImpl<T>(T sample, object[] input)
{
return input.Cast<T>().ToArray();
}
You could do make the ConvertArrayImpl call with reflection manually of course, instead of using dynamic typing.
Also note that all of these will fail if the input array is empty...
Similar to Jon's solution you can do without dynamic and make use of the Array type:
public Array Convert(Array a) {
if (a.GetLength(0) == 0){
return new int[0];
}
var type = a.GetValue(0).GetType();
var result = Array.CreateInstance(type, a.GetLength(0));
for (int i = 0; i < a.GetLength(0); i++) {
result.SetValue(a.GetValue(i), i);
}
return result;
}

Generic way to send an array collection containing only a part of a more complex structure

Let's say a program like this:
class MyClass
{
public int Numbers;
public char Letters;
}
class Program
{
static void Main()
{
var mc = new MyClass[5];
for (var i = 0; i < 5; i++)
{
mc[i].Numbers = i + 1;
mc[i].Letters = (char) (i + 65);
}
}
}
Now, let's suppose an 'X' method that requires ALL the numbers contained in the object mc, in a separate array, that's sent as a parameter.
My first idea is a for, a new integers array, and copy one by one onto its respective position. But, what if the MyClass gets different, now it has strings and floats, and I wanna pull out the strings, now the for has to be completely redefined in its inside part to create the needed array for another 'X' method.
I know of cases where Linq helps a lot, for example, generics for Sum, Average, Count and another numeric functions, and of course, it's combination with lambda expressions.
I'm wondering if something similar exists to make the above arrays of MyClass (and anothers of course) in a faster-generic way?
If you want to use LINQ, you can do something like the following:
int [] numbers = mc.Select<MyClass, int>(m => mc.Number).ToArray();
To make it more generic than that, it gets a bit more complicated, and you may need reflection, or dynamic objects. A simple example with reflection would be:
private TValue[] ExtractFields<TClass, TValue>(TClass[] classObjs, string fieldName)
{
FieldInfo fInfo = typeof(TClass).GetField(fieldName, BindingFlags.Public | BindingFlags.Instance);
if (fInfo != null && fInfo.FieldType.Equals(typeof(TValue)))
return classObjs.Select<TClass, TValue>(c => (TValue)fInfo.GetValue(c)).ToArray();
else
throw new NotSupportedException("Unidentified field, or different field type");
}
And then just call it like:
int [] fields = ExtractField<MyClass, int>(mc, "Number");
If you are using C# 4.0, then you may use dynamic
class MyClass
{
public dynamic Numbers;
public char Letters;
}
EDIT: based on comments
I am not sure if this is what you want:
int[] arr = mc.Select(a => a.Numbers).ToArray<int>();
or without casting
int[] arr = mc.Select(a => a.Numbers).ToArray();
Why not just use Dictionary<int, char>, or if the data type is unknown then simply Dictionary<object, object>
If your goal is to generate a new array which is detached from the original array, but contains data copied from it, the most generic thing you could do would be to define a method like:
T my_array[]; // The array which holds the real things
U[] CopyAsConvertedArray<U>(Func<T,U> ConversionMethod);
That would allow one to generate a new array which extracts items from the original using any desired method.

What is the need Indexers in C#

Today I've gone through what indexers are, but I am bit confused. Is there really a need for indexers? What are the advantages of using an indexer..... thanks in advance
I guess the simplest answer is to look at how you'd use (say) List<T> otherwise. Would you rather write:
string foo = list[10];
or
string foo = list.Get(10);
Likewise for dictionaries, would you rather use:
map["foo"] = "bar";
or
map.Put("foo", "bar");
?
Just like properties, there's no real need for them compared with just named methods following a convention... but they make code easier to understand, in my view - and that's one of the most important things a feature can do.
Indexers let you get a reference to an object in a collection without having to traverse the whole collections.
Say you have several thousands of objects, and you need the one before last. Instead of iterating over all of the items in the collection, you simply use the index of the object you want.
Indexers do no have to be integers, so you can use a string, for example, (though you can use any object, so long as the collection supports it) as an indexer - this lets you "name" objects in a collection for later retrieval, also quite useful.
I think zedo got closest to the real reason IMHO that they have added this feature. It's for convenience in the same way that we have properties.
The code is easer to type and easier to read, with a simple abstraction to help you understand.
For instance:
string[] array;
string value = array[0];
List<string> list;
string value = list[0]; //Abstracts the list lookup to a call similar to array.
Dictionary<string, int> map;
int value = map["KeyName"]; //Overloaded with string lookup.
Indexers allow you to reference your class in the same way as an array which is useful when creating a collection class, but giving a class array-like behavior can be useful in other situations as well, such as when dealing with a large file or abstracting a set of finite resources.
yes , they are very use of
you can use indexers to get the indexed object.
Taken from MSDN
Indexers are most frequently implemented in types whose primary purpose is to encapsulate an internal collection or array.
Full Story
for some reason, use indexer can let you create meaningful index to store or map your data. then you can get it from other side by the meaningful index.
using System;
/* Here is a simple program. I think this will help you to understand */
namespace Indexers
{
class Demo
{
int[] a = new int[10];
public int Lengths
{
get
{
return a.Length;
}
}
public int this[int index]
{
get
{
return a[index];
}
set
{
a[index] = value;
}
}
}
class Program
{
static void Main(string[] args)
{
Demo d = new Demo(); // Notice here, this is a simple object
//but you can use this like an array
for (int i = 0; i < d.Lengths; i++)
{
d[i] = i;
}
for (int i = 0; i < d.Lengths; i++)
{
Console.WriteLine(d[i]);
}
Console.ReadKey();
}
}
}
/*Output:
0
1
2
3
4
5
6
7
8
9
*/

Categories

Resources