Написание методов расширения с помощью Action / Func / Delegates / Lambda в VB и C # - PullRequest
3 голосов
/ 05 мая 2009

Во-первых, я не могу разобраться с функциональными / лямбда-аспектами .NET 3.5. Я использую эти функции каждый день в LINQ, но моя проблема заключается в понимании реализации и ее значении (Lambda? System.Func? И т. Д.)

Имея это в виду, как будет достигнуто следующее:

В качестве примера я хотел бы иметь метод Extension для List (Of T), который устанавливает свойства всех объектов в List на определенное значение и возвращает обновленный List (Of T). Это будет называться так:

VB:

 Dim someList As List(Of TextBox) =  (New List(Of TextBox)).UpdateExtension(Function(txtb) txtb.Text = "something")

C #:

List<TextBox> someList = (new List<TextBox>()).UpdateExtension(txtb => txtb.Text = "something");

Как будет выглядеть метод Extension в VB и C #?

т.е:

 <Extension()> _
 Public Function UpdateExtension(Of T)(ByVal source As List(Of T), ByVal predicate As ??) As List(Of T)
        '??
 End Function

ура!

EDIT

Как уже отмечали многие, вышеприведенного можно более или менее достичь с помощью .ForEach (). Но меня интересует понимание того, как реализовано что-то вроде .ForEach (), т. Е. Меня интересует реализация решения вышеуказанной проблемы.

Ответы [ 3 ]

2 голосов
/ 05 мая 2009

На самом деле, вы используете соответствующие методы расширения. Это почти комбинация Select и ForEach. Похоже, вам нужен метод, который позволит вам одновременно изменять элементы списка и возвращать исходное перечисление. Следующее должно помочь вам.

VB.Net

<Extension()> _
Public Function UpdateExtension(Of T)(ByVal source As IEnumerable(Of T), ByVal del As Action(Of T)) As IEnumerable(Of T)
  For Each cur in source
    del(cur)
  Next
  Return source
End Function

C #

public static IEnumerable<T> UpdateExtension<T>(this IEnumerable<T> source, Action<T> del) {
  foreach ( var cur in source ) {
    del(cur);
  }
  return source;
}
2 голосов
/ 05 мая 2009

За исключением того, что вы изменили бы список на месте, а не возвращали новый, это всего лишь вызов .ForEach().

Чтобы действительно понять, как это работает, подумайте больше о IEnumerable с, чем списках. Подумайте, почему два приведенных ниже выражения имеют одинаковый результат и , почему последнее обычно предпочтительнее:

MyEnumerable.Count() > 2
MyEnumerable.Skip(2).Any()

Чтобы помочь в этом, заново внедрите некоторые стандартные расширения IEnumerable, используя ключевое слово C # yield. Как только вы действительно поймете, почему 2-й результат лучше, вы должны быть в хорошей форме.

Что касается различных базовых типов делегатов, вам просто нужно изучить их. Думайте о Func как о вашем основном общем делегате, где вы указываете тип аргумента и тип возвращаемого значения для параметров универсального типа. Затем представьте Action как особый случай Func, где тип возвращаемого значения void, и Predicate как особый случай, когда тип возвращаемого значения bool.

1 голос
/ 05 мая 2009

Расширения реализуются в статическом классе статическими методами, которые принимают цель расширения в качестве первого параметра, которому предшествует ключевое слово this. Для реализации вашего примера я бы сделал:

public static class ListBoxExtensions
{
  public static List<TextBox> SetToValue(this List<TextBox> txtBoxes, string sValue)
  {
    txtBoxes.ForEach(txtBox => txtBox.Text = sValue);
    return txtBoxes;
  }
}

и использовать это в форме Windows с 3 текстовыми полями:

private void Form1_Load(object sender, EventArgs e)
{
  List<TextBox> boxes = new List<TextBox>
                        {
                          textBox1,
                          textBox2,
                          textBox3
                        }.SetToValue("Hello");
}

Извините - не говорите на VB.

Надеюсь, это поможет.

...