Please help with List and Generic Method

sipi41

Member
Joined
Apr 12, 2020
Messages
6
Programming Experience
1-3
Thank you for reading! I'm getting a list of objects (from a dbcontext), then I created a method to pass this list to a Local Function, the method accepts the list but when I try to loop, instead of being able to show the content of my object members I get an error saying: "'T' does not contain a definition for 'Id' and no accessible extension method 'Id' accepting a first argument of type 'T' could be found (are you missing a using directive or an assembly reference?) " And this problem is not only with Id, I can't access any of the properties, please check the code: would you please help me find what I am missing? thank you for your advice.

C#:
    public class Fruit
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

    public class ImporterController : Controller    {        
        public IActionResult Racks()
        {

            List<Fruit> Fruits = new List<Fruit> { 
                 new Fruit{Id = 1, Name = "Mango"}
                 , new Fruit{Id =2, Name="Banana" }
            };

            ProcessMyList<Fruit>(Fruits);

            void ProcessMyList<T>( List<T> list)
            {

                foreach (T thing in list)
                {
                    Debug.WriteLine(thing.Name);   /* LINE CAUSING THE PROBLEM...*/
                }

            }

            return Json("done");
        }
    }
 

Attachments

  • 1599946254183.png
    1599946254183.png
    238 KB · Views: 24
Last edited:
Unfortunately, C# generics are not quite like C++ templates, where the compiler resolves things fully at compile time. So in your code above, the compiler does not know at line 18 that the T is actually a OldRackAustin and has a public property called Name.

So possible fixes are replace T with OldAustinRack, or take out the parameters and types on line 18 and replace line 21 with:
C#:
foreach (var item in mylist)

Edit after since you changed the code after I responded so now I need to update the line numbers and member name from Id to Name.
 
Last edited:
would you please help me find what I am missing?
There is nothing that you are missing other than expecting C# generics to work like C++ templates as I mentioned above. Once you accept that the two languages are different, you can move on to trying one of the two options for fixing things that I also mentioned above.
 
Look at your local function in isolation:
C#:
void ProcessMyList<T>( List<T> list)
{
    foreach (T thing in list)
    {
        Debug.WriteLine(thing.Name);   /* LINE CAUSING THE PROBLEM...*/
    }
}
The point of a generic method is that it can accept different types at run time. That means that, at design time, you can only use instances of that type in ways that you know will be true of all of them. By default, that means only members of the Object type. Based on that code, how could you possibly know that thing has a Name property? What if you passed that method a List<string> or a List<DataTable>? If you want to be able to access specific members of a type in a generic method then you have to use a constraint on the generic type parameter to specify that type, i.e. an interface that all types passed will implement or a base class that all passed types will inherit. If there is no common interface or base type for all the types you want to pass then you are unable to use members of those types inside the generic method.

If you're working with EF entities then you can define an interface with the common properties, e.g. Id, and add a partial class to each entity to implement that interface. You can then constrain your generic type parameter to that interface type and then access its properties in the method. That only helps with common properties. If you want to access properties specific to a particular entity then you have to write a method specific to that entity rather than a generic method.
 
Hi I know this is old but is there any solutions for this? I have also this kind of generic class and I want it to pass every object on this generic like OP does.
 
Re-read posts above. There is no solution.
 
Hi I know this is old but is there any solutions for this? I have also this kind of generic class and I want it to pass every object on this generic like OP does.
Why would you think that we'd give you a different answer? It was explained to the OP what is possible and what is not. The same possibilities exist for you, because they are the possibilities that exist for everyone.
 
Why would you think that we'd give you a different answer? It was explained to the OP what is possible and what is not. The same possibilities exist for you, because they are the possibilities that exist for everyone.
hmm.. anyway this will work. Hope it helps


I think you can do this, using reflection as stated here => in SO

C#:
foreach(var item in list)
{
    System.Reflection.PropertyInfo pi = item.GetType().GetProperty("Name");
    String name = (string)(pi.GetValue(item, null));

}
 
Your original question was how to do this with generics. There's no way to do it with generics. You have now deviated from the question and opened it up to use reflection. Notice how your code will never give you a compiler error if the object in the list doesn't have a property named "Name". You'll only discover that at runtime.
 
Unless I've misunderstood, all that's needed here is to specify a constraint on the generic name 'T' like this:


void ProcessMyList( List list):
void ProcessMyList<T>( List<T> list) where T :  Fruit

But I do wonder why the method must be generic at all, only if there are classes derived from Fruit or there's an interface used in Fruit and other classes, is a generic necessary.
 
Last edited:
Back
Top Bottom