0

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).

7
  • In the foreach loop, what type do you want v to be of? In other words, what does Convert.UInt64 accept? Commented May 28, 2020 at 13:25
  • Also "ANY TYPE" means you fall back to a generic object. There is not exactly anything else that is identical between bool and bool[]. You are better at least to have a couple of methods - one for arrays, one not for. arrays. Commented May 28, 2020 at 13:26
  • 4
    TBH, if you've got type-specific behaviour, generics probably isn't the right choice here. Commented May 28, 2020 at 13:26
  • 2
    It looks like you need more than one generic type because T : IEnumerable<T> doesn't make much sense. Something like Parameter<T, U> : IParameter<T, U> where T : IEnumerable<U> maybe? Note that bool[] does not match that constraint because it's a IEnumerable<bool> and not an IEnumreable<bool[]> And if you need to handle single items and collections, then you should separate those as you cannot deal with them in a generic way (unless you just force single items into a collection). Commented May 28, 2020 at 13:26
  • IMHO; public IEnumerable<T> Value { get ... set ... } Commented May 28, 2020 at 13:50

1 Answer 1

1

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>();
    }
Sign up to request clarification or add additional context in comments.

8 Comments

Thanks, is there anyway I could have a single "argument" in "Parameter<TEnumerable, TType>". ie. Can we somehow combine TEnumerable and TType so that I don't need to declare each param using both, eg. <bool[], bool>
Added an update. I don't really know what you're trying to achieve so I just gave it my best shot given the original code.
Oh, but will that work for both array and non-array types?
It works for anything. the type is unconstrained. but the Value property will always be an enumerable of type T
So, you are saying that I either need option 1 (to support both array and non-array types) or 2 separate implementations of that class (one for arrays and one for non-array types)?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.