0

My goal is to have a collection of various generic types which will be used to populate a drop down list. The end user will select an item from the list which will then make an API call and return data based on the custom type stored in the list.

So I created an interface that my generic class will inherit from:

using System.Type;

namespace A
{
    public interface ICustomCollection
    {
        int Index { get; set; }
        string Name { get; set; }
        string ResourceName { get; set; }
        Type TType { get; }
        Type YType { get; }
    }
}

Then the generic class which inherits from it:

using System.Type;

namespace A
{
    public class CustomCollection<T, Y> : ICustomCollection
        where T : ITType
        where Y : IYType
    {
        public int Index { get; set; }
        public string Name { get; set; }
        public string ResourceName { get; set; }

        public Type TType { get { return typeof(T); } }
        public Type YType { get { return typeof(Y); } }
    }
}

Then, I instantiate the list when the component is initialized and PerformWork once the user selects an object from the drop down list:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Reflection;
using Microsoft.JSInterop;
using Microsoft.AspNetCore.Components;

namespace A
{
    public partial class DoWork : ApiBase
    {
        public List<ICustomCollection> Items { get; set; }
        public ICustomCollection SelectedItem { get; set; }

        protected override async Task OnInitializedAsync()
        {
            Items = new List<ICustomCollection>()
            {
                new CustomCollection<ClassA, ClassB>()
                {
                    Index = 1,
                    Name = "Option 1",
                    ResourceName = "url/for/api"
                }
            };
            await base.OnInitializedAsync();
            
        }

        public async Task PerformWork()
        {
            //At this point, SelectedItem has been populated with the current ICustomCollection Item
            var selectedT = SelectedItem.TType;
            var selectedY = SelectedItem.YType;

            //fails here with conversion error
            return returnedData = await CallApiHelper((dynamic)selectedT, (dynamic)selectedY);
        }

        public async Task<string> CallApiHelper<T, Y>(T object1, Y object2)
          where T : ITType
          where Y : IYType
        {
            //base.CallApi implements the same generic type constraints as CallApiHelper
            return await base.CallApi<T, Y>(SelectedItem.ResourceName);
        }
    }
}

The error message I'm getting specifically is:

Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: The type 'System.Reflection.TypeInfo' cannot be used as type parameter 'T' in the generic type or method 'CallApiHelper<T,Y>(T, Y)'. There is no implicit reference conversion from 'System.Reflection.TypeInfo' to 'ITType'.

which makes perfect sense.

Is there a way to extract the underlying type and pass that instead? I'm open to suggestions....

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Bigg_T76
  • 61
  • 1
  • 8
  • 1
    Generic type parameters are resolved at compile time. You cannot take a value that is determined at run time and fool .NET into "inferring" its type at runtime. You will either need to construct the proper generic MethodInfo using reflection, and `Invoke()` it, or you can maintain a dictionary of delegates and look up the right one. – John Wu Jun 18 '21 at 18:55
  • @JohnWu I did attempt to extract the MethodInfo, make it generic and then invoke. However, the GetMethod() method always returned null. I'll have to dig into this a bit deeper...thanks. – Bigg_T76 Jun 18 '21 at 19:04
  • @ps2goat: results in `TType is a Type, which is not valid in the given context.` – Bigg_T76 Jun 18 '21 at 19:11
  • ah, you didn't give us those two interfaces to look at – ps2goat Jun 18 '21 at 19:12
  • I've marked this one as duplicate though I would suggest to make generic version of of interface - `ICustomCollection` and make `DoWork` generic of `` if it is suitable in your use case (i.e. `List<...> Items` will always contain the same types). – Guru Stron Jun 18 '21 at 19:18
  • @GuruStron, that was the crux of the issue. I wanted List<...> Items to contain different generic types. – Bigg_T76 Jun 18 '21 at 19:24
  • @JohnWu, thanks. I was missing the BindingFlags: BindingFlags.Instance | BindingFlags.NonPublic – Bigg_T76 Jun 18 '21 at 19:30

0 Answers0