Guillermo Perez Ответов: 3

Список и общая локальная функция


Спасибо Вам за вашу помощь! У меня есть простой список фруктов, внутри списка. Я создал универсальную локальную функцию, которая получила список<t>... проблема возникает, когда я хочу повторить этот список, программа не понимает, что такое объект <t>... в данном случае это фрукт, поэтому я не могу получить доступ ни к одному члену... пожалуйста, проверьте мой код и, если это возможно, предоставьте мне решение..., спасибо!!

Что я уже пробовал:

<pre>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");
        }
    }

3 Ответов

Рейтинг:
2

F-ES Sitecore

Если вы хотите получить доступ к свойствам элемента в списке, то вы больше не можете рассматривать его как универсальный.

void ProcessMyList(List<Fruit> list)
{
    foreach (Fruit thing in list)
    {
        Debug.WriteLine(thing.Name);
    }
}


Если вы планируете иметь другие классы, которые наследуются от fruit, то вы можете сохранить функцию generic, чтобы она работала с вашими производными классами, и добавить условие, что класс основан на Fruit.

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

    foreach (T thing in list)
    {
        Debug.WriteLine(thing.Name);
    }
}


Рейтинг:
12

Sandeep Mewara

Внутри вашего универсального метода T определяется во время выполнения, и поэтому вы не можете написать код, который обращается к свойству во время компиляции - таким образом, возникает ошибка.

Кстати, если вы получаете доступ к жестко закодированному свойству в своем универсальном методе, это как бы разрушает цель использования Generic. Предположим, вы хотите использовать тот же общий метод ProcessMyList для другого адреса класса, и в нем нет свойства "Name". Что же тогда произойдет?

Для целей обучения, чтобы решить вышеизложенное, если вы хотите получить доступ к свойствам из переданного здесь типа (Fruit), вам нужно сначала получить этот тип. Как только вы знаете тип, вы можете получить доступ к свойству соответственно.

Вариант 1: Отражение

foreach (T thing in list)
{
    var value = typeof(T).GetProperty("Name").GetValue(thing);
    Console.WriteLine(obj.Name); 
}

Вариант 2: dynamic ключевое слово
foreach (T thing in list)
{
    dynamic currobj = thing; 
    Console.WriteLine(currobj.Name); 
}

Для того чтобы сохранить этот метод все еще универсальным,
- вы можете добавить дополнительный параметр "имя свойства", чтобы получить, а затем использовать его во время отражения.
- вы можете придумать дизайн класса таким образом, чтобы все классы, наследующие от определенного интерфейса или абстрактного класса, могли использовать вышеупомянутый универсальный метод.


BillWoodruff

+5 действительно полезное объяснение

Sandeep Mewara

:большой палец вверх:

Guillermo Perez

Я также вспомнил раздел "распаковка" моей книги... (pro c#), и они сделали это так:

foreach (T вещь в списке){
var Thing = вещь как плод
if (Thing != null)...
}

Maciej Los

5 от меня тоже!

Sandeep Mewara

Спасибо Мацей!

Рейтинг:
0

Richard Deeming

Другой вариант-использовать ограничение универсального типа с интерфейсом:

public interface IHaveName
{
    string Name { get; }
}

public class Fruit : IHaveName
{
    public int Id { get; set; }
    public string Name { get; set; }
}
void ProcessMyList<T>(IEnumerable<T> list) where T : IHaveName
{
    foreach (T thing in list)
    {
        Debug.WriteLine(thing.Name);
    }
}
Вам также не нужно указывать параметр универсального типа при вызове функции. Компилятор может сделать это за вас:
List<Fruit> fruits = ...;
ProcessMyList(fruits);


Maciej Los

Мне это нравится!