Reputation: 145
C#. I have a class:
public class SQLValue<T>
{
public string nam { get; set; }
public string typ { get; set; }
public T val { get; set; }
}
now I want to create
List<SQLValue> lst = List<SQLValue>();
and add elements to it like that:
lst.Add(new List<SQLValue>(nam = "PlayerName", typ = "string", val = "Bot1"));
lst.Add(new List<SQLValue>(nam = "Ally", typ = "bool", val = true));
lst.Add(new List<SQLValue>(nam = "Levl", typ = "int", val = 2));
so I want to have a list of class that contain the value val with different types. Is it real?
Upvotes: 7
Views: 1514
Reputation: 37760
You can't.
Some base type is required. Obviously, you can always use List<object>
,
if you just want to store SQLValue<T>
instances.
But, assuming, that you want to process list items depending on nam
and typ
properties, all you can do here is to extract some base class/interface:
public interface ISQLValue
{
public string nam { get; set; }
public string typ { get; set; }
public object val { get; set; }
}
implement it in SQLValue<T>
this way:
public class SQLValue<T> : ISQLValue
{
public string nam { get; set; }
public string typ { get; set; }
public T val { get; set; }
object ISQLValue.val
{
get { return this.val; }
set { this.val = (T)value; }
}
}
and use List<ISQLValue>
to store instances and process them:
var sqlValues = new List<ISQLValue>
{
new SQLValue<string> { nam="PlayerName", typ="string", val="Bot1" }
new SQLValue<bool> { nam="Ally", typ="bool", val=true }
new SQLValue<int> { nam="Levl", typ="int", val=2 }
};
foreach (var value in sqlValues)
{
Console.WriteLine($"nam = {value.name}, typ = {value.typ}, val = {value.val}");
}
That is, in case of some batch processing, ISQLValue
will be used. But if you know T
of particular ISQLValue
, you can cast it to SQLValue<T>
and use T val
instead of object val
.
Upvotes: 6
Reputation: 7213
You can create your own class, which will hold all that information:
class MyClass
{
public string Name { get; set; }
public Type PropType { get; set; }
public object Value { get; set; }
}
then you can add items into it:
List<MyClass> list = new List<MyClass>()
{
new MyClass(){ Name = "name1", PropType = typeof(string), Value = "asdasd" },
new MyClass(){ Name = "name2", PropType = typeof(bool), Value = true },
new MyClass(){ Name = "name3", PropType = typeof(int), Value = 11 },
};
and then use it for example like this:
foreach (var item in list)
{
switch (Type.GetTypeCode(item.PropType))
{
case TypeCode.String:
break;
case TypeCode.Int32:
break;
case TypeCode.Boolean:
break;
default:
throw new NotSupportedException();
}
}
Upvotes: 1
Reputation: 14531
No, you can't do that, because generics are eventually converted into separate types.
When a generic type is first constructed with a value type as a parameter, the runtime creates a specialized generic type with the supplied parameter or parameters substituted in the appropriate locations in the MSIL. Specialized generic types are created one time for each unique value type that is used as a parameter.
Reference: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/generics-in-the-run-time
So SQLValue<int>
and SQLValue<bool>
are really two different types. As a result, you can't create a List<T>
with,
var lst = new List<SQLValue>();
Instead, you have to specify the type T
for SQLValue
as well. So something like this would be allowed,
var lst = new List<SQLValue<bool>>();
Or,
var lst = new List<SQLValue<int>>();
Also, the syntax for adding elements to such a list is incorrect in your code. For example, if you are working with a list,
var lst = new List<SQLValue<bool>>();
You can add values to it using:
lst.Add(new SQLValue<bool> { nam="Ally", typ="bool", val=true });
Or, through the constructor, if you have defined one,
lst.Add(new SQLValue<bool> ("Ally", "bool", true ));
where the constructor could be:
public SQLValue(string nam, string typ, T val )
{
this.nam = nam;
this.typ = typ;
this.val = val;
}
Upvotes: 1