IEnumerable to array of T[] - c#

Perhaps the question title is incorrect. I have the following variables
IEnumerable x = // some IEnumerable
System.Type y = // some type
How can iterate over x in order to generate an array with items of type y?
When I look into the internet I found:
public T[] PerformQuery<T>(IEnumerable q)
{
T[] array = q.Cast<T>().ToArray();
return array;
}
Note I cannot call that method PerformQuery becuase y is of type System.Type in other words calling it as PerformQuery<typeof(y)>(x); or PerformQuery<y>(x); will give me a compiler error.
edit
Here is the reason why I have that problem. I have web service where I post to it two things. The type of table I will like to query (example typeof(Customer)), and the actual string query example "Select * from customers"
protected void Page_Load(object sender, EventArgs e)
{
// code to deserialize posted data
Type table = // implement that here
String query = // the query that was posted
// note DB is of type DbContext
IEnumerable q = Db.Database.SqlQuery(table, query );
// here I will like to cast q to an array of items of type table!

You can use Expression Trees:
public static class MyExtensions
{
public static Array ToArray(this IEnumerable source, Type type)
{
var param = Expression.Parameter(typeof(IEnumerable), "source");
var cast = Expression.Call(typeof(Enumerable), "Cast", new[] { type }, param);
var toArray = Expression.Call(typeof(Enumerable), "ToArray", new[] { type }, cast);
var lambda = Expression.Lambda<Func<IEnumerable, Array>>(toArray, param).Compile();
return lambda(source);
}
}
It generates x => x.Cast<Type>().ToArray() for you, with Type known at runtime.
Usage:
IEnumerable input = Enumerable.Repeat("test", 10);
Type type = typeof(string);
Array result = input.ToArray(type);

var ObjectsOfType_y = x.OfType<object>().Where(x => x.GetType() == y);
Notice that this will return an IEnumerable<object>, though. There's no way around that because the type that y (Type) represents is unknown at compile time.

According to my understanding, IENumerable contains only one type. If I understand what you're trying to do, IENumerable already only contains only objects of type y. If y needs to change, you can write an extension method:
public static T[] ToArray<T>(this IEnumerable<T> source)
{
int length = System.Linq.Enumerable.Count(source);
T[] newArray = new T[length];
int i = 0;
foreach(T item in source)
{
newArray[i] = item;
}
return newArray;
}

Related

Convert type List<object> to 'T'

I'm trying to write a generic function:
private T Convert<T>(List<object> list) where T : new()
{
if (typeof(T).IsArray)
{
T array = new T();
// ... convert here
return array;
}
}
In this scenario, I know that the objects in list should be the same type as the array of T. For example, if T is System.Int32[] then I'd expect the objects in list to all be Int32.
However, T is not always an array. In other cases, it may be a value type or even some other reference type.
How can I convert this List<object> to T given these assumptions?
UPDATE
This seems to be working within a set of given assumptions:
private T Convert<T>(List<object> list)
{
// ... code omitted for brevity
if (typeof(T).IsArray)
{
// big assumption here
Type elementType = Type.GetType(typeof(T).FullName.Replace("[]", string.Empty));
Array array = Array.CreateInstance(elementType, list.Count);
for (int i = 0; i < list.Count; i++)
{
array.SetValue(list[i], i);
}
return (T)Convert.ChangeType(array, typeof(T));
}
}
You can use the ancient ArrayList to create an array of the desired type. (It's pretty much the only thing it is good for.)
private T Convert<T>(List<object> list)
{
if (typeof(T).IsArray)
{
var tmp = new ArrayList(list);
return (T)(object)tmp.ToArray(typeof(T).GetElementType());
}
return (T)list.First();
}
Fiddle
Note: You should probably add some error handling, e.g. if the caller specified a T that doesn't make sense for the list.

Cannot deconstruct dynamic object while calling dll's method

Say I have some dll with a method like so:
public (string, List<string>) MyMethod(NameValueCollection Settings, MyClass1 params)
{
//do something
return (result, errorList);
}
Now from my main project I will call it like so:
var shipmentNumber = string.Empty;
var errorList = new List<string>;
var DLL = Assembly.LoadFile($#"{AppDomain.CurrentDomain.BaseDirectory}{appSettings[$"{parameters.TestCase}_DLL_Name"]}");
Type classType;
classType = DLL.GetType($"{appSettings[$"{parameters.TestCase}_DLL_Name"].Replace(".dll", "")}.MyService");
dynamic d = Activator.CreateInstance(classType);
(result, errorList)= d.MyMethod(appSettings, params);
However this gives me an error on the last line shown here Cannot deconstruct dynamic objects. Is there a way I could return tuple properly here?
As per the compiler error message, you can't use deconstruction with dynamic values.
In this case you know that your method is going to return a tuple, so either cast the result to that:
(result, errorList) = ((string, List<string>)) d.MyMethod(appSettings, params);
Or assign to a tuple and then deconstruct:
(string, List<string>) tuple = d.MyMethod(appSettings, params);
(result, errorList) = tuple;
Note that the casting looks a bit funky with the double parentheses, but they're necessary: the outer parentheses are for casting syntax; the inner parentheses are for tuple type syntax.
Here's a complete simple example:
using System;
class Test
{
static void Main()
{
dynamic d = new Test();
// Variables we want to deconstruct into
string text;
int number;
// Approach 1: Casting
(text, number) = ((string, int)) d.Method();
// Approach 2: Assign to a tuple variable first
(string, int) tuple = d.Method();
(text, number) = tuple;
}
public (string, int) Method() => ("text", 5);
}

Detect if an object is a ValueTuple

I have a use case where I need to check if a value is a C# 7 ValueTuple, and if so, loop through each of the items. I tried checking with obj is ValueTuple and obj is (object, object) but both of those return false. I found that I could use obj.GetType().Name and check if it starts with "ValueTuple" but that seems lame to me. Any alternatives would be welcomed.
I also have the issue of getting each item. I attempted to get Item1 with the solution found here: How do I check if a property exists on a dynamic anonymous type in c#? but ((dynamic)obj).GetType().GetProperty("Item1") returns null. My hope was that I could then do a while to get each item. But this does not work. How can I get each item?
Update - more code
if (item is ValueTuple) //this does not work, but I can do a GetType and check the name
{
object tupleValue;
int nth = 1;
while ((tupleValue = ((dynamic)item).GetType().GetProperty($"Item{nth}")) != null && //this does not work
nth <= 8)
{
nth++;
//Do stuff
}
}
Structures do not inherit in C#, so ValueTuple<T1>, ValueTuple<T1,T2>, ValueTuple<T1,T2,T3> and so on are distinct types that do not inherit from ValueTuple as their base. Hence, obj is ValueTuple check fails.
If you are looking for ValueTuple with arbitrary type arguments, you can check if the class is ValueTuple<,...,> as follows:
private static readonly Set<Type> ValTupleTypes = new HashSet<Type>(
new Type[] { typeof(ValueTuple<>), typeof(ValueTuple<,>),
typeof(ValueTuple<,,>), typeof(ValueTuple<,,,>),
typeof(ValueTuple<,,,,>), typeof(ValueTuple<,,,,,>),
typeof(ValueTuple<,,,,,,>), typeof(ValueTuple<,,,,,,,>)
}
);
static bool IsValueTuple2(object obj) {
var type = obj.GetType();
return type.IsGenericType
&& ValTupleTypes.Contains(type.GetGenericTypeDefinition());
}
To get sub-items based on the type you could use an approach that is not particularly fast, but should do the trick:
static readonly IDictionary<Type,Func<object,object[]>> GetItems = new Dictionary<Type,Func<object,object[]>> {
[typeof(ValueTuple<>)] = o => new object[] {((dynamic)o).Item1}
, [typeof(ValueTuple<,>)] = o => new object[] {((dynamic)o).Item1, ((dynamic)o).Item2}
, [typeof(ValueTuple<,,>)] = o => new object[] {((dynamic)o).Item1, ((dynamic)o).Item2, ((dynamic)o).Item3}
, ...
};
This would let you do this:
object[] items = null;
var type = obj.GetType();
if (type.IsGeneric && GetItems.TryGetValue(type.GetGenericTypeDefinition(), out var itemGetter)) {
items = itemGetter(obj);
}
Regarding the part of the question "How can I get each item?"...
Both ValueTuple and Tuple both implement ITuple, which has a length property and an indexer property. So a the following console app code lists the values to the console:
// SUT (as a local function)
IEnumerable<object> GetValuesFromTuple(System.Runtime.CompilerServices.ITuple tuple)
{
for (var i = 0; i < tuple.Length; i++)
yield return tuple[i];
}
// arrange
var valueTuple = (StringProp: "abc", IntProp: 123, BoolProp: false, GuidProp: Guid.Empty);
// act
var values = GetValuesFromTuple(valueTuple);
// assert (to console)
Console.WriteLine($"Values = '{values.Count()}'");
foreach (var value in values)
{
Console.WriteLine($"Value = '{value}'");
}
Console output:
Values = '4'
Value = 'abc'
Value = '123'
Value = 'False'
Value = '00000000-0000-0000-0000-000000000000'
This is my solution to the problem. A PCL compatible extension class. Special thanks to #dasblinkenlight and #Evk for helping me out!
public static class TupleExtensions
{
private static readonly HashSet<Type> ValueTupleTypes = new HashSet<Type>(new Type[]
{
typeof(ValueTuple<>),
typeof(ValueTuple<,>),
typeof(ValueTuple<,,>),
typeof(ValueTuple<,,,>),
typeof(ValueTuple<,,,,>),
typeof(ValueTuple<,,,,,>),
typeof(ValueTuple<,,,,,,>),
typeof(ValueTuple<,,,,,,,>)
});
public static bool IsValueTuple(this object obj) => IsValueTupleType(obj.GetType());
public static bool IsValueTupleType(this Type type)
{
return type.GetTypeInfo().IsGenericType && ValueTupleTypes.Contains(type.GetGenericTypeDefinition());
}
public static List<object> GetValueTupleItemObjects(this object tuple) => GetValueTupleItemFields(tuple.GetType()).Select(f => f.GetValue(tuple)).ToList();
public static List<Type> GetValueTupleItemTypes(this Type tupleType) => GetValueTupleItemFields(tupleType).Select(f => f.FieldType).ToList();
public static List<FieldInfo> GetValueTupleItemFields(this Type tupleType)
{
var items = new List<FieldInfo>();
FieldInfo field;
int nth = 1;
while ((field = tupleType.GetRuntimeField($"Item{nth}")) != null)
{
nth++;
items.Add(field);
}
return items;
}
}
hackish one liner
type.Name.StartsWith("ValueTuple`")
(can be extended to check the digit at the end)

Convert from object[] to double[] on C#

I have a function that generates objects with different data in it (the function fills the object with random data, according to the type). The function returns an object[] as the type is only know at runtime (and it's passed to the function as a parameter).
double[] values;
values = factory.GetData(typeof(double), 10);
Unfortunately I get a compiler error:
Cannot convert from object[] to double[].
How can I cast the object[] programmatically?
EDIT:
this is the original function:
public object[] GetData(Type type, int howMany)
{
var data = new List<object>();
for (var i = 0; i < howMany; i++)
{
data.Add(Convert.ChangeType(GetRandom(type), type));
}
return data.ToArray();
}
where GetRandom() create an object of type type and assign it a random value (random int, random string, random double, only basic types)
and this is the GetRandom() function:
public T GetRandom<T>()
{
var type = typeof(T);
if (type == typeof(int))
{
return prng.Next(0, int.MaxValue);
}
if (type == typeof(double))
{
return prng.NextDouble();
}
if (type == typeof(string))
{
return GetString(MinStringLength, MaxStringLength);
}
if (type == typeof(DateTime))
{
var tmp = StartTime;
StartTime += new TimeSpan(Interval * TimeSpan.TicksPerMillisecond);
return tmp;
}
}
Use Array.ConvertAll:
values = Array.ConvertAll(factory.GetData(typeof(double), 10), item => (double)item);
Example:
object[] input = new object[]{1.0, 2.0, 3.0};
double[] output = Array.ConvertAll(input, element => (double)element); // [1.0, 2.0, 3.0]
Note you might get InvalidCastException if one of the items can't be casted to double.
You could:
values = factory.GetData(typeof(double), 10).Cast<double>().ToArray();
If factory.GetData return an array of object of double, you can use:
values = factory.GetData(typeof(double), 10).Cast<double>().ToArray();
Now all the answers (mostly) actually answer the question there are none that actually talk about using Generics instead. Now this may not fit your direct bill but can be added quite easily to resolve the issue and require no knowledge from a calling application how to understand the return values.
This is simple. Just define an overload that accepts a Generic Type (note T)
public T[] GetData<T>(int count)
{
Type tType = typeof(T);
//.. TODO: Generate our array.. anyway you wish..
List<T> list = new List<T>();
for (int i = 0; i < count; i++)
list.Add(Activator.CreateInstance<T>());
return list.ToArray();
}
So this is a basic example and callable by:
Factory factory = new Factory();
var arr = factory.GetData<double>(10); //returns a typed array of double
Now from a caller perspective we know that the data we are receivining is typed to double or the type they provide.
This is an alternative to your initial question. However if your array of objects will not always be the type originally requested then this will not work.
EDIT
To define the array is really up to how you define your objects but lets just take your initial concept and adapt it to the same above:
public T[] GetData<T>(int count)
{
Type tType = typeof(T);
//.. TODO: Generate our array.. anyway you wish..
List<T> list = new List<T>();
for (int i = 0; i < count; i++)
list.Add((T)GetRandom(tType));
return list.ToArray();
}
In the new sample we are assuming that the Method GetRandom() will return the Type requested. The type requested is generic based on the typereference (typeparam) T. We can get the actual type by calling typeof(T). Now in this example we simply directly cast the GetRandom() object response (I am assuming GetRandom() returns a type of object.
Final Edit
As stated in the comments your can change your object GetRandom(Type type) to T GetRandom<T>(). This will allow you to generate specific types for your random. I would suggest reading up on Generics https://msdn.microsoft.com/en-us/library/512aeb7t.aspx
Now one thing that is not quickly apparent is that what you name your generic is up to you. You dont have to use T and you can use multiple generics in one method call, as with many methods you probably already use.
** Final Final Edit **
Just to elaborate how you could change your GetRandom method to a generic we still have to work with the type object its really the only one that allows for direct boxing conversion for any type. You could use the as keyword but that will could leave to other problems. Now the GetRandom(Type type) method is returning a random object of the type. As stated this is limited to a few types so lets just put together an example.
The first thing to understand is how to handle our various types. Now personally I like to define an interface. So lets define an interface for all our Random Types to inherit. As below:
interface IRandomTypeBuilder
{
object GetNext();
}
As simple interface to return a random typed entity of with the method of GetNext(). This will return a typed response based on the generic parameter T.
Now some simple implementations of this interface.
class DoubleRandomBuilder : IRandomTypeBuilder
{
static Random rng = new Random();
public object GetNext()
{
return rng.NextDouble() * rng.Next(0, 1000);
}
}
class IntRandomBuilder : IRandomTypeBuilder
{
static Random rng = new Random();
public object GetNext()
{
return rng.Next(int.MinValue, int.MaxValue);
}
}
class StringRandomBuilder : IRandomTypeBuilder
{
static Random rng = new Random();
static string aplha = "abcdefghijklmnopqrstuvwxyz";
public object GetNext()
{
string next = "";
for (int i = rng.Next(4, 10), j = i + rng.Next(1, 10); i < j; i++)
next += aplha[rng.Next(0, aplha.Length)];
return next;
}
}
class BoolRandomBuilder : IRandomTypeBuilder
{
static Random rng = new Random();
public object GetNext()
{
return rng.Next(0, 2) % 2 == 0;
}
}
Yes these are very simple but we have 4 different types that all define the GetNext() method and return a random value for the type. Now we can define the GetRandom<T>() method.
public T GetRandom<T>()
{
Type tType = typeof(T);
IRandomTypeBuilder typeGenerator = null;
if (tType == typeof(double))
typeGenerator = new DoubleRandomBuilder();
else if (tType == typeof(int))
typeGenerator = new IntRandomBuilder();
else if (tType == typeof(string))
typeGenerator = new StringRandomBuilder();
else if (tType == typeof(bool))
typeGenerator = new BoolRandomBuilder();
return (T)(typeGenerator == null ? default(T) : typeGenerator.GetNext());
}
Assuming GetData does return doubles boxed as arrays, you can use Cast() to cast all elements to double:
values=factory.GetData(typeof(double), 10).Cast<double>().ToArray();
or you can use OfType() to filter out values that are not double
values=factory.GetData(typeof(double), 10).OfType<double>().ToArray();
A better option though would be to rewrite GetData as a generic method and return a T[]

C# Get the type of a multidimensional array

How can I get the type of the inner-most elements of a multidimensional array?
var qq = new int[2,3]{{1,2,3}, {1,2,4}};
var t = qq.GetType().ToString();//is "System.Int32[,]"
var t2 = ??; // should be "System.Int32"
I'd like to get the innermost element type regardless of the number of dimensions of the array (Rank).
Use GetElementType():
var t2 = qq.GetType().GetElementType().ToString();
When you found there's a lack of methods out of the box of what you need, you can always write your own extension methods.
public static Type GetEssenceType(this Type node) {
for(Type head=node, next; ; node=next)
if(null==(next=node.GetElementType()))
return node!=head?node:null;
}
It returns the inner-most element type(which I called the essence type) if the given type(named node in the code) was a type which has element type; otherwise, null.
Edit:
Type has a internal method does the similar thing:
internal virtual Type GetRootElementType()
{
Type elementType = this;
while (elementType.HasElementType)
{
elementType = elementType.GetElementType();
}
return elementType;
}
You can create a delegate or use it via reflection:
var bindingAttr=BindingFlags.Instance|BindingFlags.NonPublic;
var method=typeof(Type).GetMethod("GetRootElementType", bindingAttr);
var rootElementType=(Type)method.Invoke(givenType, null);
Note that GetRootElementType returns the given type itself if it doesn't have element type.

Categories