Reputation: 1410
Is it possible to create and initialise an array of a reflected type in .NET in a single statement?
ie the equivalent of doing this, but using reflection:
var myArray = new String[] {"Test"};
I'm after an Array of a specific type, rather than an array of object
.
Because Array lacks a constructor that can initialise values, I've been trying to use a generic List
. This is what I've got so far, which doesn't work (no matching constructor can be found):
C#:
var myArray = (Activator.CreateInstance( typeof(List<>).MakeGenericType(typeof(string)),
System.Reflection.BindingFlags.CreateInstance
| System.Reflection.BindingFlags.Public
| System.Reflection.BindingFlags.Instance
| System.Reflection.BindingFlags.OptionalParamBinding,
null,
new[] {
(new[] {Activator.CreateInstance( typeof(string),
System.Reflection.BindingFlags.CreateInstance
| System.Reflection.BindingFlags.Public
| System.Reflection.BindingFlags.Instance
| System.Reflection.BindingFlags.OptionalParamBinding,
null,
new[] { "Test".ToCharArray() },
null)
}).AsEnumerable()
},
null));
VB.NET:
Dim myArray = Activator.CreateInstance( GetType(List(Of)).MakeGenericType(GetType(String)),
Reflection.BindingFlags.CreateInstance _
Or Reflection.BindingFlags.Public _
Or Reflection.BindingFlags.Instance _
Or Reflection.BindingFlags.OptionalParamBinding,
Nothing,
{
{Activator.CreateInstance( GetType(String),
Reflection.BindingFlags.CreateInstance _
Or Reflection.BindingFlags.Public _
Or Reflection.BindingFlags.Instance _
Or Reflection.BindingFlags.OptionalParamBinding,
Nothing,
{"Test".ToCharArray()}, Nothing)
}.AsEnumerable()
},
Nothing)
This question is asked out of curiosity about what is possible, rather than what should be done (as in I don't care if the solution is hideous, this is just for fun). I'll happily accept answers for either language, if this is possible!
Upvotes: 1
Views: 1452
Reputation: 61912
It should be easy enough with an array (like mike z's comment):
object entry = "Test";
Type type = typeof(string);
Array myArray = Array.CreateInstance(type, 1);
myArray.SetValue(entry, 0);
It creates an instance of Length
one, and then sets the entry at index zero.
It is not easier with a List<>
. You can do it like this:
object entry = "Test";
Type type = typeof(string);
object myList = Activator.CreateInstance(typeof(List<>).MakeGenericType(type));
myList.GetType().GetMethod("Add").Invoke(myList, new object[] { entry, });
It creates an instance with the default constructor, and then acquires the Add
method and invokes it with an argument "series" { entry, }
.
Using the List<>
constructor overload that takes an argument called collection
to initialize the List<>
seems a bit circular. Because to use that, you must already have some "collection" of implementing IEnumerable<string>
in advance, to create your List<>
from.
Upvotes: 0
Reputation: 14477
List<T>
have a constructor that accepts IEnumerable<T>
, but you are passing an IEnumerable<object>
to it. Hence why it failed with a MissingMethodException
.
You simply need to replace the .AsEnumerable()
with .Cast<string>()
:
var myArray = (Activator.CreateInstance(typeof(List<>).MakeGenericType(typeof(string)),
System.Reflection.BindingFlags.CreateInstance
| System.Reflection.BindingFlags.Public
| System.Reflection.BindingFlags.Instance
| System.Reflection.BindingFlags.OptionalParamBinding,
null,
new[] {
(new[] { Activator.CreateInstance(typeof(string),
System.Reflection.BindingFlags.CreateInstance
| System.Reflection.BindingFlags.Public
| System.Reflection.BindingFlags.Instance
| System.Reflection.BindingFlags.OptionalParamBinding,
null,
new[] { "Test".ToCharArray() },
null)}).Cast<string>()
},
null));
Edit: You can always cast it through reflection:
var myArray = (Activator.CreateInstance(typeof(List<>).MakeGenericType(typeof(string)),
System.Reflection.BindingFlags.CreateInstance
| System.Reflection.BindingFlags.Public
| System.Reflection.BindingFlags.Instance
| System.Reflection.BindingFlags.OptionalParamBinding,
null,
new[]
{
typeof(Enumerable).GetMethod("Cast")
.MakeGenericMethod(typeof(string))
.Invoke(null, new []
{
(new[] { Activator.CreateInstance(typeof(string),
System.Reflection.BindingFlags.CreateInstance
| System.Reflection.BindingFlags.Public
| System.Reflection.BindingFlags.Instance
| System.Reflection.BindingFlags.OptionalParamBinding,
null,
new[] { "Test".ToCharArray() },
null)})
})
},
null));
Upvotes: 2