Я оптимизирую некоторый код, который мы используем для запроса Active Directory. Один из методов извлекает всех пользователей AD, которые изменились с момента определенного обновления, что определяется свойством uSNCreated записи каталога. По сути, это эквивалент С#:
выберите * из PrincipalSearcher, где uSNCreated > какое-то значение
Код (более или менее):
public IEnumerable<UserPrincipal> GetUpdatedUsers(string samAccountName, long lastUsnChanged)
{
using (var context = new PrincipalContext(ContextType.Domain))
using (var userSearcher = new PrincipalSearcher(new UserPrincipal(context)))
{
var items = userSearcher.FindAll().Cast<UserPrincipal>();
return items.Where(x => GetUsnChanged(x) > lastUsnChanged).ToArray();
}
}
private static long GetUsnChanged(Principal item)
{
var de = item.GetUnderlyingObject() as DirectoryEntry;
if (de == null)
return 0;
if (!de.Properties.Contains("uSNCreated"))
return 0;
var usn = de.Properties["uSNCreated"].Value;
var t = usn.GetType();
var highPart = (int)t.InvokeMember("HighPart", BindingFlags.GetProperty, null, usn, null);
var lowPart = (int)t.InvokeMember("LowPart", BindingFlags.GetProperty, null, usn, null);
return highPart * ((long)uint.MaxValue + 1) + lowPart;
}
Теперь этот код работает, но повторные вызовы InvokeMember() выполняются МЕДЛЕННО. Что я хотел бы сделать, так это получить ссылку на свойства HighPart и LowPart, чтобы я мог вызывать их снова и снова без накладных расходов, связанных с необходимостью «повторно открывать» их каждый раз при вызове InvokeMember().
Я бы хотел, чтобы я мог сделать что-то вроде
static PropertyInfo highProp = highProp
?? t.GetProperty("HighPart", BindingFlags.GetProperty);
highPart = (int)highProp.GetValue(usn);
К сожалению, t.GetProperty() всегда возвращает значение null. Глядя на результаты, возвращаемые GetProperties(), GetMethods() и GetMembers(), кажется, что нет видимых "HighPart" или "LowPart", к которым я могу получить доступ, даже при использовании BindingFlags.NonPublic - просто __ComObject кажется, не раскрывает их (хотя я могу вызвать использование InvokeMember())
Есть ли способ решить эту проблему, или пора признать поражение?