Automatic unboxing - c#

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

Related

Issues with concatenating after Array.Select in C#

I'm working on the following code for a uni project:
public Order[] collapse()
{
return ConcatArrays(Rondes.Select(rs => rs.collapse()));
}
public static T[] ConcatArrays<T>(T[][] list)
{
var result = new T[list.Sum(a => a.Length)];
int offset = 0;
for (int x = 0; x < list.Length; x++)
{
list[x].CopyTo(result, offset);
offset += list[x].Length;
}
return result;
}
Here rs is of a custom type Ronde, and rs.collapse() returns Order[]. The goal of the first function is to compute rs.collapse() for every rs, and concatenate these arrays. How do I resolve the following error:
The type arguments for method ConcatArrays<T>(T[][]) cannot be inferred from the usage. Try specifying the type arguments explicitly.
I tried to follow the reccomendation by changing all T's to Order, but that did not change the error message. Any help is greatly appreciated!! Thanks in advance!
EDIT:
I have now changed the first function to:
public Order[] collapse()
{
if (Rondes == null) { return new Order[0]; }
return OrderLijsten.ConcatArrays<Order>(Rondes.Select(rs => rs.collapse()));
}
but now i get this error:
Error CS1503 Argument 1: cannot convert from 'System.Collections.Generic.IEnumerable<Grote_Opdracht.Classes.Order[]>' to 'Grote_Opdracht.Classes.Order[][]'
The error message gives you a pretty clear explanation: Your Select call returns an IEnumerable but this ConcatArrays implementation expects an array (of arrays).
You could either make the method use IEnumerable (but then you would enumerate multiple times), or call ToArray to make an array. In this case, I would prefer a combination, and also use ToList instead, which should be the most performant option:
public Order[] Collapse()
{
// make sure to iterate only once
var arrays = Rondes.Select(rs => rs.collapse()).ToList();
return ConcatArrays(arrays);
}
// use IEnumerable to be more flexible
public static T[] ConcatArrays<T>(IEnumerable<T[]> arrays)
{
var result = new T[arrays.Sum(a => a.Length)];
int offset = 0;
foreach (var a in arrays)
{
a.CopyTo(result, offset);
offset += a.Length;
}
return result;
}

How to determine the type of an generic array element with reflection?

What I'm trying to do is without generic types is simple.
SomeType[] s = new SomeType[5];
for(int i = 0; i < 5: i++){
s[i]= new SomeType();
}
Using generics this is what I have so far.
private static T TypeMapper<T>(dynamic handle) {
if (typeof(T).IsArray)
{
Type elementType = typeof(T).GetElementType();
int arrayLength = handle.Length;
Array array = Array.CreateInstance(elementType, arrayLength);
//??? How to get the type of an generic array element
Type typeOfthis = typeof(array[0]).GetElementType();
for (int i = 0; i < arrayLength; i++)
{
//??? How to create an instance from it.
array[i] = new typeOfthis ();
}
T obj = (T)(object)array;
return obj;
}
else
{}
Then calling the TypeMapper function with.
dynamic t = new TextSpan[4];
var result = TypeMapper<TextSpan[]>(t)
How can I get the type of an generic array element.
Type typeOfthis = typeof(array[0]).GetElementType();//Not Working
And how to create an instance from it.
array[i] = new typeOfthis ();
Your help is highly appreciated.
The Solution of Rubidium 37 was marked as correct
Type typeofitem = array.GetType().GetElementType();
instead of
Type typeOfthis = typeof(array[0]).GetElementType();
and
array.SetValue(Activator.CreateInstance(typeofitem), i);
instead of
array[i] = new typeOfthis ();
Thanks also for the other solutions here, but they quite missing the point that I can pass SomeType[] or SomeType as T to TypeMapper<T>(dynamic handle).
Then I can then derive from the type if it is an array or not and process the handle as needed.
offtopic
The long breath reason behind it is to marshal javascript types from v8 used by the v8dotnet wrapper which returns objects which have an equal behavior like dynamic objects.Instead of explaining what an InternalHandle handle is I reduced it to dynamic so that it is comprehensible.
When you have an array element, you have an object, that can be a different type from other array elements (like a derived type).
Then you can get the type of a single element array as you do for any standalone object.
You should replace
Type typeOfthis = typeof(array[0]).GetElementType();
with
Type typeOfthis = array[0].GetType();
Whereas, when you want create an object of any type, you can simply using Activator.CreateInstance or retrieve one ConstructorInfo from the Type.
Replace
array[i] = new typeOfthis ();
with
array[i] = Activator.CreateInstance(typeOfthis);
Just for you yo know..
- Remember that Activator.CreateInstance will try to call a parameterless constructor of the type you pass to it, then that type need to have such a constructor.
- The object you create need to be compatible with the array's Element type (assignable to it, like a derived class).
- If you know in advance that all elements of the array are (or should be) of the same type, then you don't need to get the type for each element; instead, typeof(T).GetElementType() should be enough.
- If the element type is a class and you don't need to assign concrete values because they are assigned later, or you know that the elementi type is struct, then you don't need to fill the array.
A part of that details, if you want to create a new array, given its length and the (concrete) type of its elements, you can try one of the following:
public static Array CreateAndFillArray(Type type, int length)
{
var result = Array.CreateInstance(type, length);
for (int ixItem = 0; ixItem < result.Length; ixItem++)
result.SetValue(Activator.CreateInstance(type), ixItem);
return result;
}
public static T[] CreateAndFillArray<T>(int length)
{
var type = typeof(T);
var result = new T[length];
for (int ixItem = 0; ixItem < result.Length; ixItem++)
result[ixItem] = (T)Activator.CreateInstance(type);
return result;
}
public static T[] CreateAndFillArray<T>(int length)
where T : new()
{
var result = new T[length];
for (int ixItem = 0; ixItem < result.Length; ixItem++)
result[ixItem] = new T();
return result;
}
Regards,
Daniele.
You need to learn something more about generics (and generalization in general). If you want to fill an array with default instances of a type, you can use this:
void ConstructAll<T>(T[] array) where T : new()
{
for (var i = 0; i < array.Length; i++)
{
array[i] = new T();
}
}
However, this doesn't really look like a good idea. What problem are you trying to solve? And why would you think using dynamic is a good solution?

Change ref element value with Array.ForEach?

I'm trying to use the Array.ForEach() extension method to loop through for a list of filtered elements from an array and then modify those values, unfortunately that doesn't seem to work I'm guessing because it doesn't actually modify the reference value of each element.
Is there any way to do this besides storing the results of the Array.ForEach() into a seperate array and then cloning that array to the original array? Also I know I could obviously do all of this without cloning if I use a for loop but if I could do it this way it would be cleaner and would be less code.
Here's the snippet:
Array.ForEach(Array.FindAll(starts, e => e < 0), e => e = 0);
ForEach simply isn't intended to do this - just like you wouldn't be able to do this with a foreach loop.
Personally I'd just use a for loop - it's easy to read and clear:
for (int i = 0; i < array.Length; i++)
{
// Alternatively, use Math.Max to pull up any negative values to 0
if (array[i] < 0)
{
array[i] = 0;
}
}
It really is simple - anyone will be able to understand it.
Now you could write your own extension method instead. You could write one to replace all values which satisfy a predicate with a fixed value, or you could write one to replace all values entirely... but I don't think it's really worth it. As an example of the latter:
public static void ReplaceElements<T>(this T[] array,
Func<T, T> replacementFunction)
{
// TODO: Argument validation
for (int i = 0; i < array.Length; i++)
{
array[i] = replacementFunction(array[i]);
}
}
Then call it with:
starts.ReplaceElements(x => Math.Max(x, 0));
I'd personally still use the for loop though.
(You could potentially change the above very slightly to make it take IList<T> and use Count instead. That would still work with arrays, but also List<T> etc too.)
You can do that with ref and delegates. However, I don't think it adds much value.
public delegate void RefAction<T>(ref T value);
public static void ForEachRef<T>(this T[] array, RefAction<T> action)
{
for (int i = 0; i < array.Length; ++i) action(ref array[i]);
}
You can use it as follows:
var myArray = new int[];
myArray.ForEachRef((ref int i) => i = whateverYouLike());
From the standpoint of possibility, there could be an interface IRefEnumerable<T> which iterates some container with assignable elements.
array = array.Select(x => (x < 0) ? 0: x).ToArray();

C# - Replacement for.NET ArrayList.ToArray(Type) in Silverlight

Below is a simple method I wrote (extremely simplified down so I hope it still gets the jist across) for taking a string representation of an array's elements in a string, and converting them into an actual array of those values. t is the type of the array.
DeserializeArray(string sArrayElements, out Array aValues, Type t)
{
string[] sValues = ProcessArrayElements(sArrayAsString);
ArrayList alValues = new ArrayList(sValues.Length);
for(int i = 0; i < sValues.Length; ++i)
alValues.Add(ProcessValue(sValues[ i ] ));
aValues = alValues.ToArray(t.GetElementType());
return true;
}
I would then use this method with the code below. propertyInfo is the property of an object that in this case .IsArray() == true. sArrayElements is just the string that contains the string representation of the array ("val1,val2,...,valN")
Array aValues;
if (DeserializeArray(sArrayElements, out aValues, propertyInfo.PropertyType))
propertyInfo.SetValue(oObject, aValues, null);
else
throw new FormatException("Unable to parse Array Elements: " + sArrayElements);
This works beautifully in .NET, but not in Silverlight because the ArrayList object is marked as Internal or something (can not use type because access level blah blah blah).
So I am looking for an alternative to the ArrayList.ToArray(Type). I can not just use a List<object>.ToArray() because the PropertyInfo.SetValue() call will bawk at trying to make an object[] into an Int32[] or the like.
I have tried in the DeserializeArray() method to do something like aValues = Array.CreateInstance(t.GetElementType()) but I can not use [] to assign the values and you can not assign values to the foreach(obj in objects).
I then tried changing the aValues parameter to a generic object[] array but i get the same conversion (boxing/unboxing) errors at run time when calling the Array.CreateInstance().
So yeah; I am trying to find a solution to this problem for Silverlight 4. Any help would be greatly appreciated :)
James
Not tested, but I think this should do what you want:
DeserializeArray(string sArrayElements, out Array aValues, Type t)
{
string[] sValues = ProcessArrayElements(sArrayAsString);
aValues = new Array[sValues.Length];
for(int i = 0; i < sValues.Length; ++i)
aValues.SetValue(Activator.CreateInstance(t,ProcessValue(sValues[i])),i);
return true;
}

C#: Convert T to T[]

I would like to convert T to T[] if it is an array.
static T GenericFunction<T>(T t)
{
if (t == null) return default(T);
if (t.GetType().IsArray)
{
//if object is an array it should be handled
//by an array method
return (T) GenericArrayFunction((T[])t);
}
...
}
static T[] GenericArrayFunction<T>(T[] t)
{
if (t == null) return default(T);
for (int i = 0 ; i < t.Length ; i++)
{
//for each element in array carry
//out Generic Function
if (t[i].GetType().IsArray())
{
newList[i] = GenericArrayFunction((T[])t[i]);
}
else
{
newList[i] = GenericFunction(t[i]);
}
}
...
}
Error If I try (T[])t
Cannot convert type 'T' to 'T[]'
Error If I just try to pass t
The type arguments for method 'GenericArrayFunction(T[])' cannot be inferred from the usage. Try specifying the type arguments explicitly.
Judging from your particular example, could you not define two methods and let the compiler choose the correct one when an array is passed in?
using System;
class Program
{
static T GenericFunction<T>(T t)
{
Console.WriteLine("GenericFunction<T>(T)");
return default(T);
}
static T[] GenericFunction<T>(T[] t)
{
// Call the non-array function
for(int i = 0; i < t.Length; ++i)
t[i] = GenericFunction(t[i]);
Console.WriteLine("GenericFunction<T>(T[])");
return new T[4];
}
static void Main()
{
int[] arr = {1,2,3};
int i = 42;
GenericFunction(i); // Calls non-array version
GenericFunction(arr); // Calls array version
}
}
Just because T is an array type doesn't mean that it's also an array of T. In fact, the only way that could happen would be for T to be something like object, Array or one of the interfaces implemented by arrays.
What are you really trying to do? I suspect you want to find out the element type of the array, and then call GenericArrayFunction with the appropriate T - but that won't be the same T, and you'll need to call it with reflection, which will be somewhat painful. (Not too bad, but unpleasant.)
I suspect you don't fully understand C#/.NET generics - please give us more context about the bigger picture so we can help you better.
EDIT: The reflection approach would be something like this:
private static readonly ArrayMethod = typeof(NameOfContainingType)
.GetMethod("GenericArrayFunction", BindingFlags.Static | BindingFlags.NonPublic);
...
static T GenericFunction<T>(T t)
{
if (t == null) return default(T);
if (t is Array)
{
Type elementType = t.GetType().GetElementType();
MethodInfo method = ArrayMethod.MakeGenericMethod(new[] elementType);
return (T) method.Invoke(null, new object[] { t });
}
...
}
Note that this will still fail for rectangular arrays, which get even harder to cope with.
It is not possible. T can never be T[]. T is always certain type, not just placeholder. If T is array (int[]) then T[] will be int[][].
Edit: There are some exceptions (like object is object[]), but in general case (and thats what generics are) T can't be T[]

Categories

Resources