Jump to content

  • Log In with Google      Sign In   
  • Create Account

Awesome job so far everyone! Please give us your feedback on how our article efforts are going. We still need more finished articles for our May contest theme: Remake the Classics

[C#] How do I deal with a Func when it refers to a null object?


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
11 replies to this topic

#1 Spa8nky   Members   -  Reputation: 230

Like
0Likes
Like

Posted 06 July 2011 - 09:38 AM

If I have a Function that is assigned at load time:

Func<object>

that refers to a property of a class:

() => foo.IsVisible

The delegate then keeps track of the value of IsVisible while the code is running but with one major caveat...

How can I deal with foo being 'null' in any given frame?

Something along the lines of returning 'null' or '() => { }' when foo is null instead of throwing an error.

Ad:

#2 Telastyn   Members   -  Reputation: 3329

Like
2Likes
Like

Posted 06 July 2011 - 09:52 AM

Why wouldn't this work again?

() => { 
	if( foo == null ){
    	return false; // or null, or whatever.
	} else {
    	return foo.IsVisible;
   }
};


#3 Spa8nky   Members   -  Reputation: 230

Like
0Likes
Like

Posted 06 July 2011 - 02:29 PM

Why wouldn't this work again?


I would like to automatically add the check for null, rather than explicitly typing it each time, is that possible?

For example I currently use an AddParameter method to add a monitored parameter to a Dictionary which is then printed to the screen:

Dictionary<string, Func<object>> debugParams = new Dictionary<string, Func<object>>();


        public void AddParameter(string paramName, Func<object> debugParam)
        {
            if (!debugParams.ContainsKey(paramName))
            {
                debugParams.Add(paramName, debugParam);
            }
            else
            {
                debugParams[paramName] = debugParam;
            }
        }

Is there a way of adding the check for null in the AddParameter method?

Something like this:


        public void AddParameter(string paramName, Func<object> debugParam)
        {
            if (!debugParams.ContainsKey(paramName))
            {
                Func<object> func = () =>
                {
                    if (debugParam.GetType() == null)
                    {
                        return null;
                    }
                    else
                    {
                        return debugParam.Invoke();
                    }
                };

                debugParams.Add(paramName, func);
            }
        }

but which actually works as intended.

#4 ApochPiQ   Moderators   -  Reputation: 7525

Like
1Likes
Like

Posted 06 July 2011 - 02:42 PM

You can't peek into a delegate like that; you'd have to either write a thin wrapper around the delegate itself, which could do the "am I pointing to null" check for you, or just write the null check directly into the delegate code as Telastyn pointed out earlier. Either way, you have to write some code.

Sorry, nothing in life is free ;-)

#5 Washu   Senior Moderators   -  Reputation: 3113

Like
1Likes
Like

Posted 06 July 2011 - 02:44 PM

() => foo == null ? false : foo.IsVisible;

In time the project grows, the ignorance of its devs it shows, with many a convoluted function, it plunges into deep compunction, the price of failure is high, Washu's mirth is nigh.
ScapeCode - Blog | SlimDX


#6 Spa8nky   Members   -  Reputation: 230

Like
0Likes
Like

Posted 06 July 2011 - 03:38 PM

You can't peek into a delegate like that; you'd have to either write a thin wrapper around the delegate itself, which could do the "am I pointing to null" check for you, or just write the null check directly into the delegate code as Telastyn pointed out earlier. Either way, you have to write some code.

Sorry, nothing in life is free ;-)



It was certainly worth a try though. :)



#7 ApochPiQ   Moderators   -  Reputation: 7525

Like
0Likes
Like

Posted 06 July 2011 - 04:22 PM

My C# syntax is rusty, but you could always write a "make_safe_delegate" that accepts an object and a delegate; if the object is null, return a dummy delegate that simply returns a default value. If the object is not null, return the provided delegate. Then instead of directly passing your property-accessor delegates to the dictionary, you wrap them in make_safe_delegate first.

Just a thought.

#8 return0   Members   -  Reputation: 360

Like
0Likes
Like

Posted 06 July 2011 - 04:52 PM

Why would foo be null? Broken object model?

#9 Spa8nky   Members   -  Reputation: 230

Like
0Likes
Like

Posted 06 July 2011 - 04:54 PM

My C# syntax is rusty, but you could always write a "make_safe_delegate" that accepts an object and a delegate; if the object is null, return a dummy delegate that simply returns a default value. If the object is not null, return the provided delegate. Then instead of directly passing your property-accessor delegates to the dictionary, you wrap them in make_safe_delegate first.

Just a thought.


It's a good thought. My C# skills (and programming skills) are only 2 years old but I came up with this:


    class MakeSafeDelegate
    {
        Func<object> safeFunc;

        public MakeSafeDelegate(object o, Func<object> func)
        {
            safeFunc = () => o == null ? null : func.Invoke();
        }

        public Func<object> Func
        {
            get { return safeFunc; }
        }
    }

Any suggestions for improvements?

EDIT:

Or how about this?


        public Func<object> MakeSafeFunc(object o, Func<object> func)
        {
            return () => o == null ? null : func.Invoke();
        }

EDIT2:

All of the above will not work if the object is 'null' when the Func is created though :)

#10 Telastyn   Members   -  Reputation: 3329

Like
1Likes
Like

Posted 06 July 2011 - 08:46 PM

You can't peek into a delegate like that;


This is not entirely true.

This is completely ill-advised, but if you're okay with constraining the delegates to certain forms, you can pick through their bodies and re-write them on the fly using Expression Trees:

[source lang="csharp"]using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Linq.Expressions;namespace ModifyDelegateInline { public class DebugParamMap { private Dictionary<string, Func<object>> debugParams = new Dictionary<string, Func<object>>(); public void AddParameter(string name, Expression<Func<object>> mapping) { // mapping.Body should here be of the form // Convert - MemberAccess if (mapping.Body.NodeType == ExpressionType.Convert) { var field = (mapping.Body as UnaryExpression).Operand; if (field.NodeType == ExpressionType.MemberAccess) { AddParameter(name, field as MemberExpression); return; } } else if (mapping.Body.NodeType == ExpressionType.MemberAccess) { AddParameter(name, mapping.Body as MemberExpression); return; } throw new ArgumentException("Expression must be of the form '() => member'"); } private void AddParameter(string name, MemberExpression expr) { var obj = expr.Expression; if (obj == null) { // Then it's a static property. Assume it's good. this.debugParams.Add(name, Expression.Lambda<Func<object>>(Expression.Convert(expr, typeof(object))).Compile()); } else { Expression<Func<object>> newbie = Expression.Lambda<Func<object>>( Expression.Condition( Expression.Equal( obj, Expression.Convert(Expression.Constant(null), obj.Type) ), Expression.Convert(Expression.Constant(null), expr.Type), expr, expr.Type ) ); this.debugParams.Add(name, newbie.Compile()); } } public void Print() { foreach (var entry in this.debugParams) { Console.WriteLine("{0}: {1}", entry.Key, entry.Value()); } } } public class Test { public string Name = null; } class Program { static int something = 42; static void Main(string[] args) { var map = new DebugParamMap(); var test = new Test(); map.AddParameter("foo", () => something); map.AddParameter("testname", () => test.Name); map.Print(); } }}[/source]

#11 ApochPiQ   Moderators   -  Reputation: 7525

Like
0Likes
Like

Posted 06 July 2011 - 09:41 PM

OK, OK, fine, you can do it if you abuse the hell out of a reflection system Posted Image


My point wasn't that it's strictly impossible (hell, why not introspect the instruction code bytestream at runtime by peeking at the memory page(s) of the executable image?) but rather that the language doesn't directly let you ask "will this delegate attempt to dereference a null."

#12 Telastyn   Members   -  Reputation: 3329

Like
0Likes
Like

Posted 07 July 2011 - 07:22 AM

Eh, that's not too much abuse...

Regardless, C# does not have a Safe Navigation Operator like some other languages.




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS