Вместо того, чтобы бросать код на вас, есть два понятия, которые являются ключом к пониманию того, как JS обрабатывает обратные вызовы и асинхронность. (это даже слово?)
Есть три вещи, о которых вам нужно знать; Очередь; цикл события и стек
. В широких упрощенных терминах цикл событий подобен диспетчеру проекта, он постоянно прослушивает любые функции, которые хотят запускать и взаимодействовать между очереди и стека.
while (queue.waitForMessage()) {
queue.processNextMessage();
}
Как только он получает сообщение для запуска чего-то, он добавляет его в очередь. Очередь - это список вещей, которые ждут выполнения (например, ваш запрос AJAX). Представьте себе это так:
1. call foo.com/api/bar using foobarFunc
2. Go perform an infinite loop
... and so on
Когда одно из этих сообщений будет исполнено, оно выталкивает сообщение из очереди и создает стек, стек - это все, что нужно выполнить JS для выполнения инструкции в сообщение. Таким образом, в нашем примере ему говорят позвонить foobarFunc
function foobarFunc (var) {
console.log(anotherFunction(var));
}
. Так что все, что foobarFunc должно выполнить (в нашем случае anotherFunction
), будет вставлено в стек. исполняемый, а затем забытый - цикл события затем переместится на следующую вещь в очереди (или прослушивает сообщения)
. Главное здесь - порядок выполнения. Это
Когда вы совершаете вызов с использованием AJAX для внешней стороны или выполняете любой асинхронный код (например, setTimeout), Javascript зависит от ответ, прежде чем он сможет продолжить.
Большой вопрос, когда он получит ответ? Ответ в том, что мы не знаем, поэтому цикл событий ждет, когда это сообщение скажет: «Эй, забери меня». Если JS просто ждал этого сообщения синхронно, ваше приложение замерзнет, и оно сосать. Таким образом, JS продолжает выполнение следующего элемента в очереди, ожидая, пока сообщение не будет добавлено обратно в очередь.
Вот почему с асинхронной функциональностью мы используем вещи, называемые обратными вызовами. Это похоже на обещание буквально. Как и в I , обещание что-то вернуть в какой-то момент jQuery использует специальные обратные вызовы, называемые deffered.done
deffered.fail
и deffered.always
(среди других). Вы можете увидеть их все здесь
Итак, вам нужно передать функцию, которая в какой-то момент будет выполнена с переданными ей данными.
Поскольку обратный вызов не выполняется немедленно, но в более позднее время важно передать ссылку на функцию, которую она не выполнила. поэтому
function foo(bla) {
console.log(bla)
}
, поэтому большую часть времени (но не всегда) вы пройдете foo
не foo()
. Надеюсь, это будет иметь смысл. Когда вы сталкиваетесь с такими вещами, которые кажутся запутанными, я настоятельно рекомендую полностью прочитать документацию, чтобы хотя бы понять ее. Это сделает вас намного лучшим разработчиком.
Используйте флаги BindingFlags.NonPublic
и BindingFlags.Instance
FieldInfo[] fields = myType.GetFields(
BindingFlags.NonPublic |
BindingFlags.Instance);
Вы можете сделать это, как с помощью свойства:
FieldInfo fi = typeof(Foo).GetField("_bar", BindingFlags.NonPublic | BindingFlags.Instance);
if (fi.GetCustomAttributes(typeof(SomeAttribute)) != null)
...
Вы можете получить доступ к любому частному полю произвольного типа с таким кодом:
Foo foo = new Foo();
string c = foo.GetFieldValue<string>("_bar");
Для этого вам нужно определить метод расширения, который сделают для вас работу:
public static class ReflectionExtensions {
public static T GetFieldValue<T>(this object obj, string name) {
// Set the flags so that private and public fields from instances will be found
var bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
var field = obj.GetType().GetField(name, bindingFlags);
return (T)field?.GetValue(obj);
}
}
typeof(MyType).GetField("fieldName", BindingFlags.NonPublic | BindingFlags.Instance)
Получить значение частной переменной с помощью Reflection:
var _barVariable = typeof(Foo).GetField("_bar", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(objectForFooClass);
Установить значение для частной переменной с помощью Reflection:
typeof(Foo).GetField("_bar", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(objectForFoocClass, "newValue");
Где objectForFooClass - это непустой экземпляр для типа класса Foo .
Вот некоторые методы расширения для простых get и set private fields и properties (properties with setter):
пример использования:
blockquote>public class Foo { private int Bar = 5; } var targetObject = new Foo(); var barValue = targetObject.GetMemberValue("Bar");//Result is 5 targetObject.SetMemberValue("Bar", 10);//Sets Bar to 10
Код:
/// <summary> /// Extensions methos for using reflection to get / set member values /// </summary> public static class ReflectionExtensions { /// <summary> /// Gets the public or private member using reflection. /// </summary> /// <param name="obj">The source target.</param> /// <param name="memberName">Name of the field or property.</param> /// <returns>the value of member</returns> public static object GetMemberValue(this object obj, string memberName) { var memInf = GetMemberInfo(obj, memberName); if (memInf == null) throw new System.Exception("memberName"); if (memInf is System.Reflection.PropertyInfo) return memInf.As<System.Reflection.PropertyInfo>().GetValue(obj, null); if (memInf is System.Reflection.FieldInfo) return memInf.As<System.Reflection.FieldInfo>().GetValue(obj); throw new System.Exception(); } /// <summary> /// Gets the public or private member using reflection. /// </summary> /// <param name="obj">The target object.</param> /// <param name="memberName">Name of the field or property.</param> /// <returns>Old Value</returns> public static object SetMemberValue(this object obj, string memberName, object newValue) { var memInf = GetMemberInfo(obj, memberName); if (memInf == null) throw new System.Exception("memberName"); var oldValue = obj.GetMemberValue(memberName); if (memInf is System.Reflection.PropertyInfo) memInf.As<System.Reflection.PropertyInfo>().SetValue(obj, newValue, null); else if (memInf is System.Reflection.FieldInfo) memInf.As<System.Reflection.FieldInfo>().SetValue(obj, newValue); else throw new System.Exception(); return oldValue; } /// <summary> /// Gets the member info /// </summary> /// <param name="obj">source object</param> /// <param name="memberName">name of member</param> /// <returns>instanse of MemberInfo corresponsing to member</returns> private static System.Reflection.MemberInfo GetMemberInfo(object obj, string memberName) { var prps = new System.Collections.Generic.List<System.Reflection.PropertyInfo>(); prps.Add(obj.GetType().GetProperty(memberName, System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.FlattenHierarchy)); prps = System.Linq.Enumerable.ToList(System.Linq.Enumerable.Where( prps,i => !ReferenceEquals(i, null))); if (prps.Count != 0) return prps[0]; var flds = new System.Collections.Generic.List<System.Reflection.FieldInfo>(); flds.Add(obj.GetType().GetField(memberName, System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.FlattenHierarchy)); //to add more types of properties flds = System.Linq.Enumerable.ToList(System.Linq.Enumerable.Where(flds, i => !ReferenceEquals(i, null))); if (flds.Count != 0) return flds[0]; return null; } [System.Diagnostics.DebuggerHidden] private static T As<T>(this object obj) { return (T)obj; } }
Я натолкнулся на это, ища это в google, поэтому понимаю, что я натыкаюсь на старый пост. Однако для GetCustomAttributes требуются два параметра.
typeof(Foo).GetFields(BindingFlags.NonPublic | BindingFlags.Instance)
.Where(x => x.GetCustomAttributes(typeof(SomeAttribute), false).Length > 0);
Второй параметр указывает, хотите ли вы искать иерархию наследования
. Одна вещь, о которой вам нужно знать, когда вы размышляете о частных членах, заключается в том, что если ваше приложение работает в режиме ожидания (как, например, когда вы работаете в среде общего хостинга), он не найдет их - параметр BindingFlags.NonPublic будет просто проигнорирован.
Да, однако вам нужно установить флаги Binding для поиска частных полей (если вы ищете члена вне экземпляра класса).
Необходимый флаг привязки: System. Reflection.BindingFlags.NonPublic
Я использую этот метод лично
if (typeof(Foo).GetFields(BindingFlags.NonPublic | BindingFlags.Instance).Any(c => c.GetCustomAttributes(typeof(SomeAttribute), false).Any()))
{
// do stuff
}