Convert array type to singular - c#

In C# is it possible to convert an array type to singular - for use with Activator.CreateInstance. Take this for example:
void Main()
{
var types = new[] { typeof(ExampleClass), typeof(ExampleClass[]) };
var objects = new List<object>();
foreach (var type in types)
{
// possibly convert type here? (from array to singular - type[] to type)
Debug.WriteLine($"{type}");
objects.Add(Activator.CreateInstance(type));
}
}
// Define other methods and classes here
public class ExampleClass
{
public int X;
public int Y;
}
Gets the following output:

If I understand your Question right you might want something like this using Type.GetElementType() via reflection.
static void Main(string[] args)
{
var types = new[] { typeof(ExampleClass), typeof(ExampleClass[]) };
var objects = new List<object>();
foreach (var type in types)
{
var typeInstance = type.GetElementType();
if (typeInstance != null)
{
Debug.WriteLine($"{typeInstance}");
objects.Add(Activator.CreateInstance(typeInstance));
}
else
{
objects.Add(Activator.CreateInstance(type));
}
}
}
public class ExampleClass
{
public int X;
public int Y;
}

If I understand your question correctly, you want to get the base-type of an array, right? That should be quite easy with the IsArray property of the type, simply check each entry of your list like this:
private static Type GetTypeOrElementType(Type type)
{
if (!type.IsArray)
return type;
return type.GetElementType();
}
Btw, if you want to create a new Array of that specific type, you can use Array.CreateInstance instead of Activator.CreateInstance

Found this works:
void Main()
{
var types = new[] { typeof(ExampleClass), typeof(ExampleClass[]) };
var objects = new List<object>();
foreach (var type in types)
{
Debug.WriteLine($"{type}");
objects.Add(type.IsArray
? Activator.CreateInstance(type, 1)
: Activator.CreateInstance(type));
}
}
// Define other methods and classes here
public class ExampleClass
{
public int X;
public int Y;
}

Related

C# How To Initialize a generic Class with a type variable

disclaimer I'm a newbie in understanding Reflection.
abstract class BaseClass<T>
{
public abstract T Value { get; }
public virtual bool CheckValue(string input)
{
return true;
}
}
class NotBaseClassA : BaseClass<string>
{
public override string Value { get => "Yes";}
public override bool CheckValue(string input)
{
return 1 == 2;
}
}
class NotBaseClassB : BaseClass<int>
{
public override int Value { get => 1; }
}
class ManyBaseClasses
{
public NotBaseClassB notBaseClassB;
public NotBaseClassA notBaseClassA;
}
class Programm
{
public void Main()
{
foreach (PropertyInfo pi in typeof(ManyBaseClasses).GetProperties())
{
string input = Console.ReadLine();
//Get the generic type of the propertyInfo
//BaseClass<type> bt = new BaseClass<type>();
//Instantiate BaseClass not as a var So I can do
//BaseClass.CheckValue(input)
}
}
}
I'm just trying to do like the title says. So i saw this answer but the answer returns a 'var' but I cant call my CheckValue() function from a type var. (Or i dont think I can?). What i Need is to Instantiate my BaseClass<> with the correct type from a type variable and not as a var, as a proper BaseClass obj so i can then call my functions.
Edit 1 : i've already managed to get the generic type in the variable by doing something like that
public static System.Type GetBaseClassType(this System.Type type)
{
System.Type[] types = new System.Type[]{ };
while (type != null && type != typeof(object) || types.Length == 0)
{
types = type.GetGenericArguments();
if (types.Length > 0)
{
return types[0];
}
type = type.BaseType;
}
return null;
}
The base class is not relevant in this case, as it's abstract, so you actually want to instantiate the derived class.
All you need to do to create it is
Activator.CreateInstance(pi.PropertyType)
Then you will need to use reflection on that result to call CheckValue, because there is no common base type or interface.
It might be easier to extract the non-generic code into a BaseBaseClass which is not generic, which means you don't need reflection for the second step.
abstract class BaseBaseClass
{
public virtual bool CheckValue(string input)
{
return true;
}
}
abstract class BaseClass<T> : BaseBaseClass
{
public abstract T Value { get; }
}
Then you can just do
((BaseBaseClass) Activator.CreateInstance(pi.PropertyType)).CheckValue(someInput)
I've done that before, but it was a long time ago. You have to create instance via reflection and call the method via reflection.
foreach (PropertyInfo pi in typeof(ManyBaseClasses).GetProperties())
{
string input = Console.ReadLine();
//Get the generic type of the propertyInfo
var propType = pi.Type;
Type[] typeArgs = { propType };
var genType = d1.MakeGenericType(typeArgs);
//BaseClass<type> bt = new BaseClass<type>();
object bt = Activator.CreateInstance(genType);
//Instantiate BaseClass not as a var So I can do
//BaseClass.CheckValue(input)
MethodInfo method = typeof(bt).GetMethod("CheckValue"));
method.Invoke(bt, new[] { input });
}

Is there a way to invoke a templated class on an anonymous type?

Here's some code to give the idea.
public class C<T> { }
public class X {
void M() {
var V = new { W = 1 };
var X = new C<V>(); // illegal
}
}
So V is a variable of an anonymous type and I would like to instantiate class C with V as its argument. This requires a type argument, which I cannot supply.
This questions is similar but the answer is not much help in my case: Why can't I instantiate a generic class inferring types from anonymous objects?
The question behind the question is that I'm trying to do what IEnumerable can do.
Should have made it clear: I would really prefer not to do this by manipulating object or Type because you lose the benefits of strong typing and Intellisense.
For anyone interested, the project that needs this is described here: http://www.andl.org/2016/07/andl-net-making-progress/.
You can use type inference if you have a factory method:
public class C<T>
{
public C(T t)
{
// ...
}
}
public static class Factory
{
public static C<T> Create<T>(T t)
{
return new C<T>(t);
}
}
public class Thing
{
void Foo()
{
var x = new { y = "z" };
//var thing = new C(x); - doesn't work, you need to specify the generic parameter
var thing = Factory.Create(x); // T is inferred here
}
}
You can't do that since V is instance of anonymous type, not a type name itself.
You can create this type dynamically (assuming parameterless constructor in C<>):
var X = typeof (C<>)
.MakeGenericType(V.GetType())
.GetConstructor(Type.EmptyTypes)
.Invoke(new object[0]);
You need a type, you can use pass object as a type.
Sample code:
public class C<T>
{
public T _t { get; set; }
public C(T t)
{
_t = t;
}
public void TestMethod()
{
Console.WriteLine(_t.ToString());
}
}
public class X
{
public void M()
{
var V = new { W = 1 };
var X = new C<object>(V); // everything is an object.
X.TestMethod();
}
}

Create open constructed type from string

Let's say I have the following class.
MyClass<T>
{
public void MyMethod(T a, List<T> b, List<Tuple<T, string>> c) {}
}
I can get the type of the arguments of the method as follow
Type testType = typeof(MyClass<>);
MethodInfo myMethodInfo = testType.GetMethod("MyMethod");
Type[] paramTypes = myMethodInfo.GetParameters().Select(pi => pi.ParameterType);
How can I manually create an array containing the same open types as paramTypes from a string? For ex from
var typesAsStr = new string[] {"T", "List`1[T]", "List`1[Tuple`2[T, string]]"};
If I had MyClass<int>, I could do something like Type.GetType(fullQualifiedNameOfArg) for each argument, but here I want to keep the generic argument T:
I can't create "a": I can't do Type.GetType("T")
I can almost create "b": I can do Type.GetType("List `1"), but the info on "T" is not yet present
I don't know how to create "c"
I ended up needing this when converting a Mono.Cecil type into a .net type: Cecil gives me the info on a method named "MyMethod" with arguments "T", "List<T>" and "List<Tuple<T, string>>". I then want to get that method using reflection (if there are several methods with the same name and argument numbers, I have to check the args to know which one it is), that's why I'd want to have a way to transform what Cecil tells me into what .Net knows, to be able to compare with what's in paramTypes.
I've also seen several other people asking how to convert a Mono.Cecil type into a .Net one, so that's also why I thought I'd try.
You can get T using strings, you do it by calling GetType with the string name of MyClass and then getting the generic arguments of the resulting type. From there you can build up the other open generic types using MakeGenericType. You have to work from the inside out by constructing the most nested types first. To do it automatically across differing methods would require some string parsing to get to the nested types. For the sake of comparing .Net methods against Cecil methods, #Tengiz might have a better approach.
To run the code, update the string name of MyClass to have the correct namespace for your environment.
private static void Main(string[] args) {
// change 'yournamespace'
Type testType = Type.GetType("yournamespace.MyClass`1");
Type[] testTypeGenericArgs = testType.GetGenericArguments();
// Get T type from MyClass generic args
Type tType = testTypeGenericArgs[0];
Type genericListType = Type.GetType("System.Collections.Generic.List`1");
// create type List<T>
Type openListType = genericListType.MakeGenericType(testTypeGenericArgs[0]);
Type genericTuple = Type.GetType("System.Tuple`2");
Type stringType = Type.GetType("System.String");
// create type Tuple<T, string>
Type openTuple = genericTuple.MakeGenericType(new[] { tType, stringType });
// create type List<Tuple<T, string>>
Type openListOfTuple = genericListType.MakeGenericType(openTuple);
Type[] typesFromStrings = new[] { tType, openListType, openListOfTuple };
// get method parameters per example
Type myClassType = typeof(MyClass<>);
MethodInfo myMethodInfo = myClassType.GetMethod("MyMethod");
Type[] paramTypes = myMethodInfo.GetParameters().Select(pi => pi.ParameterType).ToArray();
// compare type created from strings against types
// retrieved by reflection
for (int i = 0; i < typesFromStrings.Length; i++) {
Console.WriteLine(typesFromStrings[i].Equals(paramTypes[i]));
}
Console.ReadLine();
}
I found this so interesting, that I had to create something myself, and present it to the world... and after a couple hours of exploration, here is what I got...
The extension method for Type: GetMethodByString
This is very simple: get a type and then call the method passing a string that represents the method you want:
var type = typeof(MyType<>);
type.GetMethodByString("MyMethod(T, List`1[T], List`1[Tuple`2[T, String]])")
Sample program
class Program
{
public static void Main()
{
var t1 = typeof(MyType<>);
var mi11 = t1.GetMethodByString("MyMethod(T, List`1[T], List`1[Tuple`2[T, String]])");
var mi12 = t1.GetMethodByString("Method[X](X, T)");
var mi13 = t1.GetMethodByString("Method(List`1[T], Int32 ByRef)");
var t2 = typeof(MyType);
var mi21 = t2.GetMethodByString("Method[X, T](List`1[X], Tuple`2[X, List`1[T]])");
}
class MyType<T>
{
public void MyMethod(T a, List<T> b, List<Tuple<T, string>> c) { }
public void Method(List<T> t, out int i) { i = 0; }
public void Method<X>(X x, T t) { }
}
class MyType
{
public int Method<X, T>(List<X> x, Tuple<X, List<T>> tuple)
{
return 1;
}
}
}
TypeExtensions
public static class TypeExtensions
{
public static MethodInfo GetMethodByString(
this Type type, string methodString)
{
return type.GetMethods()
.Where(mi => MethodToString(mi) == methodString)
.SingleOrDefault();
}
public static string MethodToString(MethodInfo mi)
{
var b = new StringBuilder();
b.Append(mi.Name);
if (mi.IsGenericMethodDefinition)
b.AppendFormat("[{0}]",
string.Join(", ", mi.GetGenericArguments()
.Select(TypeToString)));
b.AppendFormat("({0})", string.Join(", ", mi.GetParameters()
.Select(ParamToString)));
return b.ToString();
}
public static string TypeToString(Type t)
{
var b = new StringBuilder();
b.AppendFormat("{0}", t.Name);
if (t.IsGenericType)
b.AppendFormat("[{0}]",
string.Join(", ", t.GetGenericArguments()
.Select(TypeToString)));
return b.ToString();
}
public static string ParamToString(ParameterInfo pi)
{
return TypeToString(pi.ParameterType).Replace("&", " ByRef");
}
}
Why I didn't try to get types by name
Unfortunately, I found no way to get a type given a string, unless you guess a lot about the type being represented... so, it is quite impossible.
That explains why I did a method to find the method instead. It is much more precise... but it could eventually fail, in very rare and bizarre circumstances:
if you create a List of your own, and then two overloads of the same method, one taking the .Net List and the other taking the List you have created... then it fails
Why not parsing the input string
I found that for the purpose of looking up a method, it is enough to have a fixed syntax string, so that I can generate it from the method and compare... that have some limitations:
must use the name of the type, so C# alliases won't work (string must be named "String", int must be named "Int32" not "int")
EDIT
Performance
This solution is not very performatic, but nothing that a cache cannot solve. The method could use a dictionary, using both the Type and the string as a composite key, and look in there before trying to find the method by bulding a lot of strings and comparing all of them.
If you need thread safety on the cache dictionary, use a ConcurrentDictionary<TKey, TValue>... very nice class.
EDIT 2: Created a cached version
static ConcurrentDictionary<Type, Dictionary<string, MethodInfo>> cacheOfGetMethodByString
= new ConcurrentDictionary<Type, Dictionary<string, MethodInfo>>();
public static MethodInfo GetMethodByString(
this Type type, string methodString)
{
var typeData = cacheOfGetMethodByString
.GetOrAdd(type, CreateTypeData);
MethodInfo mi;
typeData.TryGetValue(methodString, out mi);
return mi;
}
public static Dictionary<string, MethodInfo> CreateTypeData(Type type)
{
var dic = new Dictionary<string, MethodInfo>();
foreach (var eachMi in type.GetMethods())
dic.Add(MethodToString(eachMi), eachMi);
return dic;
}
Hoppe this helps! =)
I don't think .NET allows you to create a type "T" where T is a type argument, which is yet to be specified. So, the array of Type(s) from input string array cannot be created.
However, in the second part of your question, I read that you want to identify the method which has those types given as string. That task is solvable by iterating though the arguments, creating another array of strings describing the method arguments, and then comparing the resulting and input arrays, as follows:
class MyClass<T>
{
public void MyMethod(T a, List<T> b, List<Tuple<T, string>> c) { }
}
class Program
{
static void Main(string[] args)
{
//input.
var typesAsStr = new string[] { "T", "List`1[T]", "List`1[Tuple`2[T, string]]" };
//type to find a method.
Type testType = typeof(MyClass<>);
//possibly iterate through methods instead?
MethodInfo myMethodInfo = testType.GetMethod("MyMethod");
//get array of strings describing MyMethod's arguments.
string[] paramTypes = myMethodInfo.GetParameters().Select(pi => TypeToString(pi.ParameterType)).ToArray();
//compare arrays of strings (can be improved).
var index = -1;
Console.WriteLine("Method found: {0}", typesAsStr.All(str => { index++; return index < paramTypes.Length && str == paramTypes[index]; }));
Console.ReadLine();
}
private static CSharpCodeProvider compiler = new CSharpCodeProvider();
private static string TypeToString(Type type)
{
if (type.IsGenericType) {
return type.Name + "[" + string.Join(", ", type.GetGenericArguments().Select(ga => TypeToString(ga))) + "]";
}
else if (type.IsGenericParameter) {
return type.Name;
}
//next line gives "string" (lower case for System.String).
//additional type name translations can be applied if output is not what we neeed.
return compiler.GetTypeOutput(new CodeTypeReference(type));
}
}
In the [console] output I see that your input string matches the function.
BTW, a lot of optimizations can be applied to this code if you face the performance problems, such as efficient way of working with strings, releasing CSharpCodeProvider instance maybe, etc. But the code is enough to solve the given task as questioned.
You cannot do what you are trying to do, but there is a relatively easy way of achieving the same result by entering from a different direction
Strings do not identify types uniquely
This is the basic problem with converting strings to types: when you see a T, you have no idea where it came from. The following is a valid class definition:
class Simple<T> {
public T Make(T blah) {
return blah;
}
public T Make<T>(T blah) {
return blah;
}
}
Two overloads of Make have parameters that look identical, yet they do not compare as equal. Moreover, there is absolutely no way of getting the T of the generic Make<T> without first getting the MethodInfo for the generic Make<T> - a circular dependency.
What can you do?
Instead of going for the impossible string->Type conversion, you can build a matcher that tells you if an instance of a type, including an unbounded generic type, matches a given string representation:
static bool MatchType(string str, Type type)
With this method in hand, you can walk through all available methods with a particular name, and check the types of their parameter lists one by one against the strings in your array of strings:
var typesAsStr = new [] {"T", "List`1[T]", "List`1[Tuple`2[T, string]]"};
var myMethod = typeof (Simple<>)
.GetMethods()
.SingleOrDefault(m => m.Name == "MyMethod" &&
typesAsStr
.Zip(m.GetParameters(), (s, t) => new {s, t})
.All(p => MatchType(p.s, p.t.ParameterType))
);
How do you implement the MatchType method?
You can use a technique similar to Recursive Descent Parsing: tokenize your string, and then match elements of your type as you go through the chain of tokens. When a class is parameterized, get generic parameters and match them recursively. You need to pay attention to array types, but that is relatively simple as well. Take a look:
public static bool MatchType(string str, Type type) {
var queue = new Queue<Token>(Tokenize(str));
return MatchRecursive(queue, type) && (queue.Count == 0);
}
private static bool MatchRecursive(Queue<Token> tokens, Type type) {
string baseName;
if (!ReadToken(tokens, TokenType.Identifier, out baseName)) return false;
var ranks = new List<int>();
while (type.IsArray) {
ranks.Add(type.GetArrayRank());
type = type.GetElementType();
}
if (type.IsGenericType) {
if (!type.Name.StartsWith(baseName+"`") || !DropToken(tokens, TokenType.Tick)) return false;
string numStr;
int num;
if (!ReadToken(tokens, TokenType.Number, out numStr)
|| !int.TryParse(numStr, out num)
|| !DropToken(tokens, TokenType.OpenBraket)) return false;
var genParams = type.GetGenericArguments();
if (genParams.Length != num) return false;
for (var i = 0 ; i < num ; i++) {
if (i != 0 && !DropToken(tokens, TokenType.Comma)) return false;
if (!MatchRecursive(tokens, genParams[i])) return false;
}
if (!DropToken(tokens, TokenType.CloseBraket)) return false;
}
foreach (var rank in ranks) {
if (!DropToken(tokens, TokenType.OpenBraket)) return false;
for (var i = 0 ; i != rank-1 ; i++) {
if (!DropToken(tokens, TokenType.Comma)) return false;
}
if (!DropToken(tokens, TokenType.CloseBraket)) return false;
}
return type.IsGenericType || Aliases.Contains(new Tuple<string, Type>(baseName, type)) || type.Name == baseName;
}
private static readonly ISet<Tuple<string,Type>> Aliases = new HashSet<Tuple<string, Type>> {
new Tuple<string, Type>("bool", typeof(bool)),
new Tuple<string, Type>("byte", typeof(byte)),
new Tuple<string, Type>("sbyte", typeof(sbyte)),
new Tuple<string, Type>("char", typeof(char)),
new Tuple<string, Type>("string", typeof(string)),
new Tuple<string, Type>("short", typeof(short)),
new Tuple<string, Type>("ushort", typeof(ushort)),
new Tuple<string, Type>("int", typeof(int)),
new Tuple<string, Type>("uint", typeof(uint)),
new Tuple<string, Type>("long", typeof(long)),
new Tuple<string, Type>("ulong", typeof(ulong)),
new Tuple<string, Type>("float", typeof(float)),
new Tuple<string, Type>("double", typeof(double)),
new Tuple<string, Type>("decimal", typeof(decimal)),
new Tuple<string, Type>("void", typeof(void)),
new Tuple<string, Type>("object", typeof(object))
};
private enum TokenType {
OpenBraket,
CloseBraket,
Comma,
Tick,
Identifier,
Number
}
private class Token {
public TokenType Type { get; private set; }
public string Text { get; private set; }
public Token(TokenType type, string text) {
Type = type;
Text = text;
}
public override string ToString() {
return string.Format("{0}:{1}", Enum.GetName(typeof(TokenType), Type), Text);
}
}
private static bool DropToken(Queue<Token> tokens, TokenType expected) {
return (tokens.Count != 0) && (tokens.Dequeue().Type == expected);
}
private static bool ReadToken(Queue<Token> tokens, TokenType expected, out string text) {
var res = (tokens.Count != 0) && (tokens.Peek().Type == expected);
text = res ? tokens.Dequeue().Text : null;
return res;
}
private static IEnumerable<Token> Tokenize(IEnumerable<char> str) {
var res = new List<Token>();
var text = new StringBuilder();
foreach (var c in str) {
var pos = "[],`".IndexOf(c);
if ((pos != -1 || char.IsWhiteSpace(c)) && text.Length != 0) {
res.Add(new Token(
char.IsDigit(text[0]) ? TokenType.Number : TokenType.Identifier
, text.ToString())
);
text.Clear();
}
if (pos != -1) {
res.Add(new Token((TokenType)pos, c.ToString(CultureInfo.InvariantCulture)));
} else if (!char.IsWhiteSpace(c)) {
text.Append(c);
}
}
if (text.Length != 0) {
res.Add(new Token(
char.IsDigit(text[0]) ? TokenType.Number : TokenType.Identifier
, text.ToString())
);
}
return res;
}
It is not quite clear to me what the exactly you need, but i believe you can use the following technique:
object[] parameters = CreateParameters(typeof(MyClass<>), "MyMethod", typeof(int));
Debug.Assert(parameters[0] is int);
Debug.Assert(parameters[1] is List<int>);
Debug.Assert(parameters[2] is List<Tuple<int, string>>);
//...
object[] CreateParameters(Type type, string methodName, Type genericArgument) {
object[] parameters = null;
MethodInfo mInfo = type.GetMethod(methodName);
if(mInfo != null) {
var pInfos = mInfo.GetParameters();
parameters = new object[pInfos.Length];
for(int i = 0; i < pInfos.Length; i++) {
Type pType = pInfos[i].ParameterType;
if(pType.IsGenericParameter)
parameters[i] = Activator.CreateInstance(genericArgument);
if(pType.IsGenericType) {
var arguments = ResolveGenericArguments(pType, genericArgument);
Type definition = pType.GetGenericTypeDefinition();
Type actualizedType = definition.MakeGenericType(arguments);
parameters[i] = Activator.CreateInstance(actualizedType);
}
}
}
return parameters;
}
Type[] ResolveGenericArguments(Type genericType, Type genericArgument) {
Type[] arguments = genericType.GetGenericArguments();
for(int i = 0; i < arguments.Length; i++) {
if(arguments[i].IsGenericParameter)
arguments[i] = genericArgument;
if(arguments[i].IsGenericType) {
var nestedArguments = ResolveGenericArguments(arguments[i], genericArgument);
Type nestedDefinition = arguments[i].GetGenericTypeDefinition();
arguments[i] = nestedDefinition.MakeGenericType(nestedArguments);
}
}
return arguments;
}

Reflection - how to get value at specified index of parameter

I'm trying to get the value of a specified index of a property using reflection.
This answer works for standard properties that are of type List<> for example, but in my case, the collection I am trying to work with is of a different format:
public class NumberCollection : List<int>
{
public NumberCollection()
{
nums = new List<int>();
nums.Add(10);
}
public new int this[int i]
{
get { return (int) nums[i]; }
}
private List<int> nums;
}
public class TestClass
{
public NumberCollection Values { get; private set; }
public TestClass()
{
Values = new NumberCollection();
Values.Add(23);
}
}
class Program
{
static void Main(string[] args)
{
TestClass tc = new TestClass();
PropertyInfo pi1 = tc.GetType().GetProperty("Values");
Object collection = pi1.GetValue(tc, null);
// note that there's no checking here that the object really
// is a collection and thus really has the attribute
String indexerName = ((DefaultMemberAttribute)collection.GetType()
.GetCustomAttributes(typeof(DefaultMemberAttribute),
true)[0]).MemberName;
// Code will ERROR on the next line...
PropertyInfo pi2 = collection.GetType().GetProperty(indexerName);
Object value = pi2.GetValue(collection, new Object[] { 0 });
Console.Out.WriteLine("tc.Values[0]: " + value);
Console.In.ReadLine();
}
}
This code gives an AmbiguousMatchException ("Ambiguous match found."). I know my collection class is somewhat contrived, but can anyone help with this?
One option is to use
var prop = Type.GetProperties()
.Where(prop => prop.DeclaringType == collection.GetType())
.First();
Change Collection.GetType() to another type if you want. But basically: loop over the properties instead of using Type.GetProperty.
If you are looking for all of the default members, you can ask for Type.GetDefaultMembers(), then examine the members to find the one that you are looking for.
Alternatively, if you know the data type of the indexer, you can call GetPropertyInfo with the type array specifier.

Generic List created at runtime

i neeed something like this in C#.. have list in class but decide what will be in list during runtime
class A
{
List<?> data;
Type typeOfDataInList;
}
public void FillData<DataTyp>(DataTyp[] data) where DataTyp : struct
{
A a = new A();
A.vListuBudouDataTypu = typeof(DataTyp);
A.data = new List<A.typeOfDataInList>();
A.AddRange(data);
}
Is this possible to do something like this ?
class A<T>
{
public readonly List<T> Data = new List<T>();
public Type TypeOfDataInList { get; private set; }
public A()
{
TypeOfDataInList = typeof(T);
}
public void Fill(params T[] items)
{
data.AddRange(items);
}
}
If you don't know the type or have multiple objects of different types, declare an instance of A like this:
A<object> myClass = new A<object>();
myClass.Fill(new object(), new object());
Otherwise if you know the type, you can do this:
A<int> myInts = new A<int>();
myInts.Fill(1, 2, 5, 7);
Yes.
class A
{
IList data;
Type typeOfDataInList;
}
public void FillData<T>(T[] data) where T : struct
{
A a = new A();
A.typeOfDataInList = typeof(T);
A.data = new List<T>(data);
}
It would be better to make the A class generic:
class A<T>
{
IList<T> data;
Type typeOfDataInList;
}
public void FillData<T>(T[] data) where T : struct
{
A<T> a = new A<T>();
a.typeOfDataInList = typeof(T);
a.data = new List<T>(data);
}
You are going to need to use reflection to instantiate an IList<T> where T is not known until runtime.
See the following MSDN article, which explains it better than I could (scroll down to the section on how to construct a generic type):
http://msdn.microsoft.com/en-us/library/b8ytshk6.aspx
Here is a short example:
Type listType = typeof(List<>);
Type runtimeType = typeof(string); // just for this example
// assert that runtTimeType is something you're expecting
Type[] typeArgs = { runtimeType };
Type listTypeGenericRuntime = listType.MakeGenericType(typeArgs);
IEnumerable o = Activator.CreateInstance(listTypeGenericRuntime) as IEnumerable;
// loop through o, etc..
You might want to consider a generic class:
public class A<T> where T : struct
{
public List<T> data;
public Type type;
}
public void FillData<DataType>(DataType[] data) where DataType : struct
{
A<DataType> a = new A<DataType>();
a.data = new List<DataType>();
a.AddRange(data);
}
System.Collections.Generic.List<T> ?

Categories

Resources