I have a generic method that returns type T (generic). In the method, if T is an array, I want to create and populate this array with data and return.
I've gotten to the point where I have a List<object?> of values and these objects are all of the type of the array elements of T (i.e. I have verified T is an array, and I have found the base type for the elements in that array, and I now have a list of objects of that base type).
What I can't figure out is how to cast the list into an array, with its type being T. I could build an array with reflection, but I still don't know how to cast that into the generic, even when they will be the exact same type.
I know this is a weird architectural design, but it is solving a complex issue.
Below is some simplified example code of what I am trying to do. The line indicated will not compile ("Cannot convert type 'object?[]' to 'T'") but is ultimately what I want to accomplish.
static void Main(string[] args)
{
Console.WriteLine("Hello, World!");
Testing test = new Testing();
DataClass[] output = test.MyMethod<DataClass[]>();
}
public class DataClass
{
public int I = 0;
public DataClass()
{
}
}
public class Testing
{
public T MyMethod<T>()
{
T result = default(T);
if (typeof(T).IsArray)
{
Type? baseType = typeof(T).GetInterfaces()
.Where(o => o.IsGenericType
&& o.GetGenericTypeDefinition() == typeof(System.Collections.Generic.IEnumerable<>))
.Select(o => o.GetGenericArguments()[0]).FirstOrDefault();
if (baseType != null)
{
List<object?> items = new List<object?>();
for (int i = 0; i < 5; i++)
{
// Just example code here to populate the array...
items.Add(Activator.CreateInstance(baseType));
}
result = (T)items.ToArray(); // <=== This is what I need to do but doesn't compile
}
}
return result;
}
}
Ideally you would have a separate function to create these arrays. This function would have a generic parameter of the element type of the array.
Then if necessary you can use reflection to run the function.
public T MyMethod<T>() where T : new()
{
T result = default(T);
if (typeof(T).IsArray)
{
var baseType = typeof(T).GetElementType();
result = (T)
this.GetType().GetMethod(nameof(CreateArray))
.MakeGenericMethod(baseType)
.Invoke();
}
else
// etc
return result;
}
public T[] CreateArray<T>() where T : new()
{
var result = new T[5];
for (int i = 0; i < result.Length; i++)
result[i] = new();
return result;
}
If it's slow then you can cache a CreateDelegate invoker in a Dictionary.
Dictionary<Type, Delegate> _delegates = new();
public T MyMethod<T>() where T : new()
{
T result = default(T);
if (typeof(T).IsArray)
{
if (!_delegates.TryGetValue(typeof(T), out var dlg) || dlg is not Func<T> invoker)
{
var baseType = typeof(T).GetElementType();
invoker =
this.GetType().GetMethod(nameof(CreateArray))
.MakeGenericMethod(baseType)
.CreateDelegate(typeof(Func<T>));
_delegates[typeof(T)] = invoker;
}
result = invoker();
}
else
// etc
return result;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With