Прежде чем я объясню, что я хочу сделать, если вы посмотрите на следующий код, поймете ли вы, что он должен делать? (обновлено - см. Ниже)
Console.WriteLine(
Coalesce.UntilNull(getSomeFoo(), f => f.Value) ?? "default value");
В C # уже есть оператор объединения нулей, который довольно хорошо работает на простых объектах, но не помогает, если вам нужен доступ к члену этого объекта.
1008 * Е.Г. *
Console.WriteLine(getSomeString()??"default");
работает очень хорошо, но здесь вам это не поможет:
public class Foo
{
public Foo(string value) { Value=value; }
public string Value { get; private set; }
}
// this will obviously fail if null was returned
Console.WriteLine(getSomeFoo().Value??"default");
// this was the intention
Foo foo=getSomeFoo();
Console.WriteLine(foo!=null?foo.Value:"default");
Поскольку с этим я часто сталкиваюсь, я подумал об использовании метода расширения (старая версия) :
public static class Extension
{
public static TResult Coalesce<T, TResult>(this T obj, Func<T, TResult> func, TResult defaultValue)
{
if (obj!=null) return func(obj);
else return defaultValue;
}
public static TResult Coalesce<T, TResult>(this T obj, Func<T, TResult> func, Func<TResult> defaultFunc)
{
if (obj!=null) return func(obj);
else return defaultFunc();
}
}
Что позволяет мне написать:
Console.WriteLine(getSomeFoo().Coalesce(f => f.Value, "default value"));
Так вы считаете этот код читабельным? Coalesce - это хорошее имя?
Редактировать 1: убрать скобки, как предложено Марком
Обновление
Мне очень понравились предложения lassevk и отзывы Groo. Поэтому я добавил перегрузки и не реализовал это как метод расширения. Я также решил, что defaultValue является избыточным, потому что вы можете просто использовать существующие ?? оператор для этого.
Это пересмотренный класс:
public static class Coalesce
{
public static TResult UntilNull<T, TResult>(T obj, Func<T, TResult> func) where TResult : class
{
if (obj!=null) return func(obj);
else return null;
}
public static TResult UntilNull<T1, T2, TResult>(T1 obj, Func<T1, T2> func1, Func<T2, TResult> func2) where TResult : class
{
if (obj!=null) return UntilNull(func1(obj), func2);
else return null;
}
public static TResult UntilNull<T1, T2, T3, TResult>(T1 obj, Func<T1, T2> func1, Func<T2, T3> func2, Func<T3, TResult> func3) where TResult : class
{
if (obj!=null) return UntilNull(func1(obj), func2, func3);
else return null;
}
public static TResult UntilNull<T1, T2, T3, T4, TResult>(T1 obj, Func<T1, T2> func1, Func<T2, T3> func2, Func<T3, T4> func3, Func<T4, TResult> func4) where TResult : class
{
if (obj!=null) return UntilNull(func1(obj), func2, func3, func4);
else return null;
}
}
Пример использования:
Console.WriteLine(
Coalesce.UntilNull(getSomeFoo(), f => f.Value) ?? "default value");
Другой образец:
public class Bar
{
public Bar Child { get; set; }
public Foo Foo { get; set; }
}
Bar bar=new Bar { Child=new Bar { Foo=new Foo("value") } };
// prints "value":
Console.WriteLine(
Coalesce.UntilNull(bar, b => b.Child, b => b.Foo, f => f.Value) ?? "null");
// prints "null":
Console.WriteLine(
Coalesce.UntilNull(bar, b => b.Foo, f => f.Value) ?? "null");