#c# #delegates #average
#c# #делегаты #среднее
Вопрос:
В приведенном ниже коде я вызываю метод расширения [в среднем] 3 раза. Сначала с помощью лямбда-выражения, затем анонимным методом и, в-третьих, с помощью делегата.
Способ с делегатом не работает. Кто-нибудь может объяснить мне, почему?
Большое спасибо заранее!
————КОД————-
using System.Linq;
using System.Collections.Generic;
class Program
{
static void Main(string[] args)
{
List<Person> people = new List<Person> {
new Person { FirstName = "William", LastName = "Schokkele", Age = 35 },
new Person { FirstName = "Bill", LastName = "Gates", Age = 50 },
new Person { FirstName = "Hanne", LastName = "Schokkele", Age = 7 }
};
Person myPerson = new Person { FirstName = "Hanne", LastName = "Schokkele", Age = 7 };
myDelegate myDel = new myDelegate(myPerson.GetAge);
double averageAge= people.Average(p => p.Age);
double averageAge2 = people.Average(delegate(Person p) { return p.Age; });
double averageAge3 = people.Average(myDel); //THIS LINE DOESNT WORK. ERROR MESSAGE LIST<Person> does not contains a definition for 'average'
}
}
public delegate int myDelegate(Person p);
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
public int GetAge(Person p)
{
return p.Age;
}
}
Ответ №1:
Вы не можете преобразовать делегат одного типа в другой в C #. Поскольку IEnumerable<T>.Average
ожидается a Func<T, int>
, это тот делегат, который вам нужно предоставить, независимо от того факта, что он имеет ту же подпись, что и myDelegate
.
Вы можете либо изменить это:
myDelegate myDel = new myDelegate(myPerson.GetAge);
в:
Func<Person, int> myDel = new Func<Person, int>(myPerson.GetAge);
или просто передайте метод в качестве параметра, который создаст для вас соответствующий делегат:
double averageAge3 = people.Average(myPerson.GetAge); // this will work
Обратите внимание, что создание GetAge
метода экземпляра (вместо статического метода) не имеет смысла, поскольку он возвращает возраст объекта, переданного в качестве параметра, вместо родительского ( this
) объекта.
Это становится очевидным, когда вы смотрите на myPerson
объект, экземпляр которого создается с «фиктивными» значениями, просто чтобы получить доступ к его GetAge
методу, который не использует ни одно из его свойств (вы могли бы просто написать double averageAge3 = people.Average(new Person().GetAge);
, и ничего бы не изменилось).
Я бы рекомендовал либо использовать анонимный метод (предпочтительный), либо создать свой GetAge
метод static
.
Ответ №2:
Для метода расширения не определена перегрузка Average(), который принимает аргумент типа myDelegate
.
Тот, который соответствует вашему случаю, следующий :
public static double Average<TSource>(this IEnumerable<TSource> source, Func<TSource, int> selector);
Вы должны использовать Func<T,TReturn>
, чтобы заставить его работать вместо myDelegate
.
Пример:
Person myPerson = new Person { FirstName = "Hanne", LastName = "Schokkele", Age = 7 };
Func<Person, Int32> myDel = myPerson.GetAge;
double averageAge = people.Average(p => p.Age);
double averageAge2 = people.Average(delegate(Person p) { return p.Age; });
double averageAge3 = people.Average(myDel);
Ответ №3:
Вы можете сделать double averageAge3 = myDel.Invoke(myPerson);
или как именно вы хотите, чтобы это выглядело?
Ответ №4:
вы должны пометить свой делегат статическим (у него нет контекста экземпляра)
public static int GetAge(Person p)
затем определите
myDelegate myDel = Person.GetAge;
или вызвать напрямую
double averageAge3 = Person.Average(myPerson.GetAge);