views:

270

answers:

3

As far as I know there is not a significantly more elegant way to write the following....

string src;
if((ParentContent!= null)
    &&(ParentContent.Image("thumbnail") != null)
    &&(ParentContent.Image("thumbnail").Property("src") != null))
    src = ParentContent.Image("thumbnail").Property("src").Value

Do you think there should be a C# language feature to make this shorter?
And if so, what should it look like?
for example, something like extending the ?? operator

string src = ParentContent??.Image("thumbnail")??.Property("width")??.Value;

Apologies for the rather contrived example, and my over-simplified solution.

+7  A: 

It's been suggested and apparently rejected by the team:

A bit more C# syntactic sugar for nulls

The proposed syntax would have looked like a.?b.?c() - very useful, and unambiguous.

I'd really like to see it too, but doesn't look like it'll happen. Maybe if enough people vote on it!

Aaronaught
+1 i'll cast my vote
Michael Buen
+7  A: 

There is no built-in syntax for doing this, but you can define an extension method to do this:

R NotNull<T, R>(this T src, Func<T, R> f) 
    where T : class where R : class {
  return src != null ? f(src) : null;
}

Now, you can rewrite your example as follows:

src = ParentContent.NotNull(p => p.Image("thumbnail")).
        NotNull(i => i.Property("src")).NotNull(src => src.Value);

It is not as nice as it may be with a syntactic support, but I'd say it's much more readable.

Note that this adds the NotNull method to all .NET types, which may be a bit inconvenient. You could solve that by defining a simple wrapper type WrapNull<T> where T : class containing only a value of type T and a method for turning any reference type into WrapNull and providing the NotNull in the WrapNull type. Then the code would look like this:

src = WrapNull.Wrap(ParentContent).NotNull(p => p.Image("thumbnail")).
        NotNull(i => i.Property("src")).NotNull(src => src.Value);

(So you wouldn't pollute the IntelliSense of every type with the new extension method)

With a bit more effort, you could also define a LINQ query operators for doing this. This is a bit overkill, but it is possible to write this (I won't include the definitions here as they are a bit longer, but it's possible in case someone is interested :-)).

src = from p in WrapNull.Wrap(ParentContent)
      from i in p.Image("thumbnail").
      from src in i.Property("src")
      select src.Value;
Tomas Petricek
I have to say, I had to read that about 5 times to properly grok it. Sometimes reading Functional code makes me regret starting out with procedural style languages instead of say LISP. Other days, I thank my sanity I didn't! :D
Serapth
@Serapth: I think that one thing is reading the implementation (and understanding how it works) and another thing is reading the user-code. Explaining how to use my `NotNull` extension method shouldn't be that difficult (maybe I just didn't do as good job here :-)).
Tomas Petricek
Oh no, I agree completely. Actually using the extension method is a no brainer and is completely legible, much more so even that the original posts recommended solution. It's the extension method itself that is horrifically difficult for me to read. That said, functional programming is not naturally intuitive to me and truth told, I have always found templated code adds a layer of confusion to the scenario as well. I think it is just how my brain is wired. I understand the syntax, what is happening and how it works, I just have to read it again and again to follow how it works.
Serapth
The only caveat about this is that it doesn't actually behave quite the same way as a bunch of nested `if` statements or ternary operators; *all* of the wrapper methods in the chain will actually be executed, even if the lambdas aren't. That's probably not going to a problem most of the time, but it's something to keep in mind - this is not a short-circuit evaluator.
Aaronaught
@Aaronaught: You can nest them: `a.NotNull(b => b.Foo.NotNull(c => c.Bar))` - then it behaves exactly like nested ifs. (I thought that the non-nested use would be more readable for the introduction)
Tomas Petricek
Such a dilema, your answer has more cool stuff in it, but Aaronaught answers the actual question a little more.
Myster
+3  A: 

We considered it for C# 4 but did not have the budget. It's a nice feature that a lot of people request, so perhaps we'll get it into a future hypothetical language version. No promises.

Eric Lippert
Someday, Eric will have had a long day and will be too tired. And on that day, he'll say, "we are considering this for the next version of C#."
Brian
Keep considering! :-)
Myster