Есть задача распарсить строку вида "127.0.0.1, 192.168.0.1" и получить последовательность с елементами типа IPAddress. Для начала нам надо разделить адреса по запятой. После убрать лишние пробелы и в конце получить елементы типа IPAddress. Заодно немешало бы выдать в Trace полученные значения. Я насчитал 4 конструкции foreach. Для сокращения количества кода создадим расширение для интерфейса IEnumerable<>, которое позволит выполнить необходимые операции без конструкции foreach.
У меня вышло так:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace System
{
public delegate void VoidFunc<T>(T arg);
public static class ForeachExtensions
{
public static IEnumerable<TResult> TakeForeach<T, TResult>(this IEnumerable<T> sequence, Func<T, TResult> func)
{
List<TResult> result = new List<TResult>();
foreach (T item in sequence)
{
result.Add(func(item));
}
return result;
}
public static IEnumerable<T> TakeForeach<T>(this IEnumerable<T> sequence, Func<T, T> func)
{
return sequence.TakeForeach<T, T>(func);
}
}
}
Первый метод служит для перебора коллекции и имеет возможность изменения в результате типа елементов последовательности. Второй метод всего лишь облегченная реализация первого метода, в котором тип елементов исходной последовательности такой же как и тип елементов в результирующей последовательности.
А теперь попробуем распарсить наш список адрессов:
[TestClass]
public class ForeachExtensionsTests
{
static readonly string testIpList = "127.0.0.1, 192.168.0.1";
[TestMethod]
public void IPListParserTestMethod()
{
IEnumerable<IPAddress> result = testIpList.Split(',').TakeForeach<string>(
delegate(string item)
{
return item.Trim();
}).TakeForeach<string, IPAddress>(
delegate(string address)
{
return IPAddress.Parse(address);
}).TakeForeach<IPAddress>(
delegate(IPAddress address)
{
System.Diagnostics.Debug.WriteLine(string.Format("IPAddress: {0}", address.ToString()));
return address;
});
}
}
В результате мы получили минимум кода без обьявления локальных переменных и конструкций foreach.
Результат выполнения бедет следующим:
IPAddress: 127.0.0.1
IPAddress: 192.168.0.1
Но это еще не все, нашу конструкцию можно еще упростить передав функцию IPAddress.Parse в качестве параметра для нашего метода а также воспользуемся лямбда выражениями для вызова функции Trim() и вынесем Trace функию в отдельный метод для повторного использования, это будет выглядеть примерно так:
[TestClass]
public class ForeachExtensionsTests
{
static readonly string testIpList = "127.0.0.1, 192.168.0.1";
public static void TraceIPAddress(IPAddress address)
{
System.Diagnostics.Debug.WriteLine(string.Format("IPAddress: {0}", address.ToString()));
}
[TestMethod]
public void IPListParserTestMethod()
{
IEnumerable<IPAddress> result = testIpList.Split(',')
.TakeForeach<string>(f=>f.Trim())
.TakeForeach<string, IPAddress>(IPAddress.Parse);
result.TakeVoidForeach<IPAddress>(ForeachExtensionsTests.TraceIPAddress);
}
}
В итоге все наши операции поместились в 4 строчки кода, читабельность которых, на порядок выше и все это благодаря новым возможностям C# 3.0, .Net 3.5 и Visual Studio 2008.
Скачать исходный код примера: BlendWorld.Extensions.zip (7,11 kb)
56eb4fc0-dc21-44b0-bafd-89bff00978b3|2|5.0
Метки:
.net,
lambda expressions,
extensions,
samples
Категории:
.Net |
C# Extensions |
Lambda Expressions |
LINQ |
Samples