-1

So I'm creating a generic method, obviously the signature therefore can take any type of object. The problem I have is I want the user to be able to either just send one object to my method, or a collection (I know, different interface from IEnumerable) of objects. Now because (T obj) could be one object, or it could be a list or an array of objects, Im not sure how to check and alter behaviour depending on if it is a collection or not.

This is what I have, and I'm getting a compiler error CS1061, T does not contain a definition for FirstOrDefault. Which makes sense, because it might not. But as far as I can tell my conditional should have checked if it does or not.

if (typeof(IEnumerable<T>).IsAssignableFrom(obj.GetType()))
        {
            foreach (var info in obj.FirstOrDefault().GetType().GetProperties())
            {
                members.Add(info.Name, info.GetValue(obj).ToString());
            }
        }
        else
        {
            foreach (var info in obj.GetType().GetProperties())
            {
                members.Add(info.Name, info.GetValue(obj).ToString());
            }
        }

In case it makes any difference, members is a Dictionary<string, string>. At this stage I'm only trying to get it to accept both collections and single objects, I can work out the behaviour later.

1 Answers1

1

You have to cast obj to IEnumerable<T> before you can access FirstOrDefault. And in your case, you can do that with the is operator.

if (obj is IEnumerable<T> e)
{
    foreach (var info in e.FirstOrDefault().GetType().GetProperties))
    ...
}
...

Your code was fine as is, except you were using obj without first casting. For example you could have done this instead:

if (typeof(IEnumerable<T>).IsAssignableFrom(obj.GetType()))
{
    var e = (IEnumerable<T>)obj;
    foreach (var info in e.FirstOrDefault().GetType().GetProperties())
    {
        members.Add(info.Name, info.GetValue(obj).ToString());
    }
    ...

As you can see though, using is is shorter and easier to read.

Kit
  • 20,354
  • 4
  • 60
  • 103
  • One more question, the code is now compiling fine and it runs, but my conditional isnt being hit, its always being skipped. I'm using List in my xunit test to pass in multiple objects right now but obj is IEnumerable e is returning false. Is it there some other way I have to cast it to check if the obj inherits from IEnumerable? – Henry Puspurs Oct 10 '20 at 17:51
  • I'd have to see more context -- maybe the whole method. – Kit Oct 10 '20 at 19:08
  • I figured it out, because as I said its a Generic method that takes any object T, when you say IEnumerable the compiler tries to fill T with the type that is being used, so its kind of trying to make it an IEnumerable of itself. So for the conditional check I used a method that returns true if T is or inherits from IEnumerable. Also this thread got closed pointing me to a thread that does not answer myquestion, and now I cant even post my own answer. – Henry Puspurs Oct 11 '20 at 19:37