Proper way to detect if a ClientObject property is already retrieved/initialized

I would say your question is already contains the correct answer to some extent.

In order to determine whether client object property is loaded or not the following methods are available:

  • ClientObject.IsPropertyAvailable method method indicates whether the specified scalar property has been retrieved or set
  • ClientObject.IsObjectPropertyInstantiated method indicates whether the specified property of the client object is instantiated

Tests

Test case 1: load scalar property only

ctx.Load(ctx.Web, w => w.Title);
ctx.ExecuteQuery();
//Results:
ctx.Web.IsObjectPropertyInstantiated("Lists")  False
ctx.Web.IsPropertyAvailable("Title")    True

Test case 2: load composite property only

ctx.Load(ctx.Web, w => w.Lists);
ctx.ExecuteQuery();
//Results:
ctx.Web.IsObjectPropertyInstantiated("Lists")  True
ctx.Web.IsPropertyAvailable("Title")    False

Test case 3: load both scalar and composite properties

ctx.Load(ctx.Web, w=>w.Lists,w=>w.Title);
ctx.ExecuteQuery();
//Results
ctx.Web.IsObjectPropertyInstantiated("Lists")  True
ctx.Web.IsPropertyAvailable("Title")    True


How to dynamically determine whether client object property is loaded or not?

Since ClientObject.IsPropertyAvailable and ClientObject.IsObjectPropertyInstantiated methods expect the property name to be specified as a string value and that could lead to typos, I usually prefer the following extension method:

public static class ClientObjectExtensions
{
    /// <summary>
    /// Determines whether Client Object property is loaded
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="clientObject"></param>
    /// <param name="property"></param>
    /// <returns></returns>
    public static bool IsPropertyAvailableOrInstantiated<T>(this T clientObject, Expression<Func<T, object>> property)
        where T : ClientObject
    {
        var expression = (MemberExpression)property.Body;
        var propName = expression.Member.Name;
        var isCollection = typeof(ClientObjectCollection).IsAssignableFrom(property.Body.Type);
        return isCollection ? clientObject.IsObjectPropertyInstantiated(propName) : clientObject.IsPropertyAvailable(propName);
    }
}

Usage

using (var ctx = new ClientContext(webUri))
{

     ctx.Load(ctx.Web, w => w.Lists, w => w.Title);
     ctx.ExecuteQuery();


     if (ctx.Web.IsPropertyAvailableOrInstantiated(w => w.Title))
     {
         //...
     }

     if (ctx.Web.IsPropertyAvailableOrInstantiated(w => w.Lists))
     {
         //...
     }
} 

The tests provided by Vadim Gremyachev only cover one half of the scenarios - where you use ctx.Load. But when you use ctx.LoadQuery the result changes:

var query = from lst in ctx.Web.Lists where lst.Title == "SomeList" select lst;
var lists = ctx.LoadQuery(query);
ctx.ExecuteQuery();
ctx.Web.IsObjectPropertyInstantiated("Lists") -> True
ctx.Web.Lists.ServerObjectIsNull -> False
ctx.Web.Lists.Count -> CollectionNotInitializedException

So once the LoadQuery has been called on a collection, you can no longer see if the collection is actually available.

Only way in this case is to detect that the exception occurs.