Правильный способ обнаружения, если свойство ClientObject уже получено/инициализировано

Если вы используете объектную модель клиента из SharePoint и получаете свойства, которые не были инициализированы или уже получены с помощью

Context.Load(property); 
Context.ExecuteQuery();

вы получите, например, a:

Microsoft.SharePoint.Client.PropertyOrFieldNotInitializedException

или

Коллекция не была инициализирована. Это не были запросы или запрос не был выполнен.

Exception.

Есть ли какой-либо надлежащий способ проверки перед доступом к этим свойствам, если они уже инициализированы/получены? Без подхода Try/Catch. Мне это не нравится.

Я хочу проверить до того, как было выброшено исключение и обработано.

Я уже проверил

IsObjectPropertyInstantiated

IsPropertyAvailable

Методы, но они действительно не помогают. IsPropertyAvaiable проверяет только скалярные свойства и не дает результата, например, Web.Lists и IsObjectPropertyInstantiated возвращает true для Web.Lists, хотя Web.Lists не был инициализирован.

Ответ 1

Я бы сказал, что ваш вопрос уже содержит правильный ответ в некоторой степени.

Чтобы определить, загружено ли свойство объекта клиента, или нет, доступны следующие методы:

Испытания

Тестовый случай 1: загрузка только скалярного свойства

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

Тестовый кейс 2: загрузить только составное свойство

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

Тестовый кейс 3: загрузка как скалярных, так и составных свойств

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


Как динамически определить, загружено ли свойство объекта клиента?

Так как ClientObject.IsPropertyAvailable и ClientObject.IsObjectPropertyInstantiated методы ожидайте, что имя свойства будет указано как строковое значение, и это может привести к опечаткам, я обычно предпочитаю следующий метод расширения:

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);
    }
}

Использование

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))
     {
         //...
     }
} 

Ответ 2

Тесты Вадима Гремячева охватывают только половину сценариев - где вы используете ctx.Load. Но когда вы используете ctx.LoadQuery, результат изменяется:

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

Итак, как только LoadQuery вызывается в коллекции, вы больше не можете видеть, действительно ли коллекция доступна.

Только в этом случае необходимо обнаружить, что это исключение.

Ответ 3

Идея использования расширения великолепна, но прекрасно работает только со списками. Расширение может выбирать между "объектом" и "скалярными" свойствами. Я думаю, что расширение будет лучше таким образом:

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 isObject = typeof(ClientObject).IsAssignableFrom(property.Body.Type); // test with ClientObject instead of ClientObjectList
    return isObject ? clientObject.IsObjectPropertyInstantiated(propName) : clientObject.IsPropertyAvailable(propName);
}