可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
Just for curiosity/convenience: C# provides two cool conditional expression features I know of:
string trimmed = (input == null) ? null : input.Trim();
and
string trimmed = (input ?? "").Trim();
I miss another such expression for a situation I face very often:
If the input reference is null, then the output should be null. Otherwise, the output should be the outcome of accessing a method or property of the input object.
I have done exactly that in my first example, but (input == null) ? null : input.Trim()
is quite verbose and unreadable.
Is there another conditional expression for this case, or can I use the ??
operator elegantly?
回答1:
Something like Groovy's null-safe dereferencing operator?
string zipCode = customer?.Address?.ZipCode;
I gather that the C# team has looked at this and found that it's not as simple to design elegantly as one might expect... although I haven't heard about the details of the problems.
I don't believe there's any such thing in the language at the moment, I'm afraid... and I haven't heard of any plans for it, although that's not to say it won't happen at some point.
EDIT: It's now going to be part of C# 6, as the "null-conditional operator".
回答2:
You can choose between a custom Nullify
class or a NullSafe
extension method as described here: http://qualityofdata.com/2011/01/27/nullsafe-dereference-operator-in-c/
The usage will be as follows:
//Groovy:
bossName = Employee?.Supervisor?.Manager?.Boss?.Name
//C# Option 1:
bossName = Nullify.Get(Employee, e => e.Supervisor, s => s.Manager,
m => m.Boss, b => b.Name);
//C# Option 2:
bossName = Employee.NullSafe( e => e.Supervisor ).NullSafe( s => s.Boss )
.NullSafe( b => b.Name );
回答3:
Currently we can only write an extension method if you don't want to repeat yourself, I'm afraid.
public static string NullableTrim(this string s)
{
return s == null ? null : s.Trim();
}
回答4:
As a workaround you can use this which is based on Maybe monad.
public static Tout IfNotNull<Tin, Tout>(this Tin instance, Func<Tin, Tout> Output)
{
if (instance == null)
return default(Tout);
else
return Output(instance);
}
Use it this way:
int result = objectInstance.IfNotNull(r => 5);
var result = objectInstance.IfNotNull(r => r.DoSomething());
回答5:
There's nothing built-in, but you could wrap it all up in an extension method if you wanted (although I probably wouldn't bother).
For this specific example:
string trimmed = input.NullSafeTrim();
// ...
public static class StringExtensions
{
public static string NullSafeTrim(this string source)
{
if (source == null)
return source; // or return an empty string if you prefer
return source.Trim();
}
}
Or a more general-purpose version:
string trimmed = input.IfNotNull(s => s.Trim());
// ...
public static class YourExtensions
{
public static TResult IfNotNull<TSource, TResult>(
this TSource source, Func<TSource, TResult> func)
{
if (func == null)
throw new ArgumentNullException("func");
if (source == null)
return source;
return func(source);
}
}
回答6:
I had the same problem I wrote a few little extension methods:
public static TResult WhenNotNull<T, TResult>(
this T subject,
Func<T, TResult> expression)
where T : class
{
if (subject == null) return default(TResult);
return expression(subject);
}
public static TResult WhenNotNull<T, TResult>(
this T subject, Func<T, TResult> expression,
TResult defaultValue)
where T : class
{
if (subject == null) return defaultValue;
return expression(subject);
}
public static void WhenNotNull<T>(this T subject, Action<T> expression)
where T : class
{
if (subject != null)
{
expression(subject);
}
}
You use it like this;
string str = null;
return str.WhenNotNull(x => x.Length);
or
IEnumerable<object> list;
return list.FirstOrDefault().WhenNotNull(x => x.id, -1);
or
object obj;
IOptionalStuff optional = obj as IOptionalStuff;
optional.WhenNotNull(x => x.Do());
There are also overloads for nullable types.