Reputation: 552
I really cannot figure out how to use generic types with IEnumerable so that I can iterate through values contained by a given generic value.
Consider the following class (note that the classes here are only for example purposes):
public class Parameter<T> : IParameter<T> where T : IEnumerable<T>
{
public List<UInt64> output = new List<UInt64>();
private T _value;
public T Value
{
get => ...;
set
{
// I want to be able to apply special treat to the value
// Value can be of any type: int, int[], bool, bool[]
foreach (var v in value)
{
output.Add(Convert.UInt64(v) + 5);
}
...
}
}
}
public interface IParameter<T> where T : IEnumerable<T>
{
T Value { get; set; }
}
I then have a test module that instantiate some parameters as per, but I cannot even compile here. I have even tried to replace bool[] to IEnumerable here below, but the compiler does not like it either.
public class TestModule : ModuleBase, ITestModule
{
public IParameter<bool[]> Test1 { get; set; } = new Parameter<bool[]>();
public IParameter<uint[]> Test2 { get; set; } = new Parameter<uint[]>();
...
public IParameter<int> Test3 { get; set; } = new Parameter<int>();
}
I did consider using overload for the Parameter() class, but I thought it to be overkill to create a class per supported type (considering it is only for the Value property).
Upvotes: 0
Views: 1645
Reputation: 20003
Your issue is that your generic parameter is specified incorrectly.
public class Parameter<T> : IParameter<T> where T : IEnumerable<T>
implies that whatever comes in of type T is an enumerable of the same type, meaning for instance a T of type bool[]
should be an IEnumerable<bool[]>
which is clearly incorrect.
One way to get it to compile is this:
public class Parameter<TEnumerable, TType> : IParameter<TEnumerable, TType> where TEnumerable : IEnumerable<TType>
{
public List<ulong> output = new List<ulong>();
private TEnumerable _value;
public TEnumerable Value
{
get => { return null; }
set
{
// I want to be able to apply special treat to the value
// Value can be of any type: int, int[], bool, bool[]
foreach (Q v in value)
{
output.Add(Convert.ToUInt64(v) + 5);
}
}
}
}
public interface IParameter<TEnumerable, TType> where TEnumerable : IEnumerable<TType>
{
TEnumerable Value { get; set; }
}
public class TestModule
{
public IParameter<bool[], bool> Test1 { get; set; } = new Parameter<bool[], bool>();
public IParameter<uint[], uint> Test2 { get; set; } = new Parameter<uint[], uint>();
public IParameter<int[], int> Test3 { get; set; } = new Parameter<int[], int>();
}
As for your additional comment, no, there's no way you can avoid having to specify the two types since IEnumerable is not a T in the form you've formulated your code. You have 2 separate parameters here and as such, you will have to use 2 generic parameters if you must do it the way you've done it.
A much simpler solution to your problem would be something like this which serves the same purpose more or less, although I don't really know your requirements so this may or may not suffice (interface omitted for clarity):
public class Parameter<TType>
{
public List<ulong> output = new List<ulong>();
private IEnumerable<TType> _value;
public IEnumerable<TType> Value
{
get => { return null; }
set
{
// I want to be able to apply special treat to the value
// Value can be of any type: int, int[], bool, bool[]
foreach (TType v in value)
{
output.Add(Convert.ToUInt64(v) + 5);
}
}
}
}
public class TestModule
{
public Parameter<bool> Test1 { get; set; } = new Parameter<bool>();
public Parameter<uint> Test2 { get; set; } = new Parameter<uint>();
public Parameter<int> Test3 { get; set; } = new Parameter<int>();
}
Upvotes: 1