Вы можете использовать Reflection для этого: (из моей библиотеки - это получает имена и значения)
public static Dictionary DictionaryFromType(object atype)
{
if (atype == null) return new Dictionary();
Type t = atype.GetType();
PropertyInfo[] props = t.GetProperties();
Dictionary dict = new Dictionary();
foreach (PropertyInfo prp in props)
{
object value = prp.GetValue(atype, new object[]{});
dict.Add(prp.Name, value);
}
return dict;
}
Эта вещь не будет работать для свойств с индексом - для этого (она становится громоздкой ):
public static Dictionary DictionaryFromType(object atype,
Dictionary indexers)
{
/* replace GetValue() call above with: */
object value = prp.GetValue(atype, ((indexers.ContainsKey(prp.Name)?indexers[prp.Name]:new string[]{});
}
Кроме того, чтобы получить только общедоступные свойства: ( см. MSDN в BindingFlags enum )
/* replace */
PropertyInfo[] props = t.GetProperties();
/* with */
PropertyInfo[] props = t.GetProperties(BindingFlags.Public)
Это работает с анонимными типами, слишком! Чтобы просто получить имена:
public static string[] PropertiesFromType(object atype)
{
if (atype == null) return new string[] {};
Type t = atype.GetType();
PropertyInfo[] props = t.GetProperties();
List propNames = new List();
foreach (PropertyInfo prp in props)
{
propNames.Add(prp.Name);
}
return propNames.ToArray();
}
И это примерно то же самое только для значений, или вы можете использовать:
GetDictionaryFromType().Keys
// or
GetDictionaryFromType().Values
Но это немного медленнее, я бы представьте себе.
Спасибо за комментарий, tec. Мне удалось найти существующую неподтвержденную ошибку Webkit, которая объясняет эту проблему: https://bugs.webkit.org/show_bug.cgi?id=35801 (EDIT: теперь исправлено!) [/ G1]
Похоже, что есть некоторые дебаты относительно того, какая часть ошибок и насколько она исправлена. Мне кажется, что это плохое поведение. Это особенно беспокоило меня, потому что, по крайней мере, в Chrome это происходит, когда код находится в сценариях, которые выполняются немедленно (до загрузки страницы), даже когда консоль открыта, всякий раз, когда страница обновляется. Вызов console.log, когда консоль еще не активна, приводит только к ссылке на объект, находящийся в очереди, а не на вывод, который будет содержать консоль. Поэтому массив (или любой объект) не будет оцениваться до тех пор, пока консоль не будет готова. Это действительно случай ленивой оценки.
Однако есть простой способ избежать этого в вашем коде:
var s = ["hi"];
console.log(s.toString());
s[0] = "bye";
console.log(s.toString());
Вызывая toString, вы создаете представление в памяти которые не будут изменены следующими операциями, которые консоль будет читать, когда она будет готова. Вывод консоли немного отличается от непосредственного передачи объекта, но он кажется приемлемым:
hi
bye
Вы можете клонировать массив с помощью Array#slice
:
console.log(s); // ["bye"], i.e. incorrect
console.log(s.slice()); // ["hi"], i.e. correct
Функция, которую вы можете использовать вместо console.log
, которая не имеет этой проблемы, выглядит следующим образом:
console.logShallowCopy = function () {
function slicedIfArray(arg) {
return Array.isArray(arg) ? arg.slice() : arg;
}
var argsSnapshot = Array.prototype.map.call(arguments, slicedIfArray);
return console.log.apply(console, argsSnapshot);
};
В случае объектов, к сожалению, лучшим методом является отладка сначала с помощью браузера, отличного от WebKit, или для записи сложной функции для клонирования. Если вы работаете только с простыми объектами, где порядок ключей не имеет значения, а функций нет, вы всегда можете:
console.logSanitizedCopy = function () {
var args = Array.prototype.slice.call(arguments);
var sanitizedArgs = JSON.parse(JSON.stringify(args));
return console.log.apply(console, sanitizedArgs);
};
Все эти методы, очевидно, очень медленные, поэтому еще больше так как с нормальным console.log
s, вы должны отключить их после завершения отладки.
Это было исправлено в Webkit, однако при использовании React framework это происходит для меня в некоторых случаях, если у вас есть такие проблемы, просто используйте, как предлагают другие:
console.log(JSON.stringify(the_array));
JSON.parse(JSON.stringify(event))
не получает правильной глубины / точности. Заявления отладчика - единственное реальное решение, которое я нашел, чтобы получить правильное представление.
– CStumph
27 July 2015 в 23:35
Похоже, что Chrome на фазе «pre compile» заменяет любой экземпляр «s» указателем на фактический массив.
. Один из способов - клонирование массива, запись вместо него следующей копии:
var s = ["hi"];
console.log(CloneArray(s));
s[0] = "bye";
console.log(CloneArray(s));
function CloneArray(array)
{
var clone = new Array();
for (var i = 0; i < array.length; i++)
clone[clone.length] = array[i];
return clone;
}
Это уже ответили, но я все равно откажусь от ответа. Я реализовал простую консольную оболочку, которая не страдает от этой проблемы. Требуется jQuery.
Он реализует только методы log
, warn
и error
, вам нужно будет добавить еще несколько, чтобы он был взаимозаменяемым с регулярным console
.
var fixedConsole;
(function($) {
var _freezeOne = function(arg) {
if (typeof arg === 'object') {
return $.extend(true, {}, arg);
} else {
return arg;
}
};
var _freezeAll = function(args) {
var frozen = [];
for (var i=0; i<args.length; i++) {
frozen.push(_freezeOne(args[i]));
}
return frozen;
};
fixedConsole = {
log: function() { console.log.apply(console, _freezeAll(arguments)); },
warn: function() { console.warn.apply(console, _freezeAll(arguments)); },
error: function() { console.error.apply(console, _freezeAll(arguments)); }
};
})(jQuery);
Из объяснения Эрика это связано с тем, что console.log()
находится в очереди, и он печатает более позднее значение массива (или объекта).
Могут быть 5 решений:
1. arr.toString() // not well for [1,[2,3]] as it shows 1,2,3
2. arr.join() // same as above
3. arr.slice(0) // a new array is created, but if arr is [1, 2, arr2, 3]
// and arr2 changes, then later value might be shown
4. arr.concat() // a new array is created, but same issue as slice(0)
5. JSON.stringify(arr) // works well as it takes a snapshot of the whole array
// or object, and the format shows the exact structure