Функция insert
здесь работает, потому что current_node.next = _node
является постоянной модификацией объекта в списке, на который указывает head
. После этого вызова, даже если current_node
собирать мусор (это просто временный указатель), у узла, на который он указывал в строке current_node.next = _node
, свойство .next
постоянно изменено.
Вот схема добавления нового узла 3
в список 1->2->nil
:
(before the `until` loop)
+---------+ +---------+
| data: 1 | | data: 2 |
| next: ----> | next: ----> [nil]
+---------+ +---------+
^ ^
| |
head current_node
(after the `until` loop; `current_node.next == nil`)
(and before `current_node.next = _node`)
+---------+ +---------+
| data: 1 | | data: 2 |
| next: ----> | next: ----> [nil]
+---------+ +---------+
^ ^
| |
head current_node
(after `current_node.next = _node`)
+---------+ +---------+ +---------+
| data: 1 | | data: 2 | | data: 3 |
| next: ----> | next: ----> | next: ----> [nil]
+---------+ +---------+ +---------+
^ ^
| |
head current_node
Кстати, этот метод insert
демонстрирует плохой дизайн; каждая вставка представляет собой O (n) линейную операцию времени, требующую обхода всего списка. Улучшенный дизайн класса LinkedList
будет предлагать указатель tail
, позволяющий O (1) вставлять постоянное время в конец списка. С другой стороны, класс может предложить add_front()
без хвостового указателя, который установит new_head.next = old_head
и head = new_head
.
Альтернативный ответ: дженерики.
public static T[] CreateProperties<T>(IProperty[] properties)
where T : class, new()
{
//Empty so return null
if (properties==null || properties.Length == 0)
return null;
//Check the type is allowed
CheckPropertyTypes("CreateProperties(Type,IProperty[])",typeof(T));
//Convert the array of intermediary IProperty objects into
// the passed service type e.g. Service1.Property
T[] result = new T[properties.Length];
for (int i = 0; i < properties.Length; i++)
{
T[i] = new T();
ServiceUtils.CopyProperties(properties[i], t[i]);
}
return result;
}
Затем Ваш код вызова становится:
Property[] props = ObjectFactory.CreateProperties<Property>(properties);
_service.SetProperties(folderItem.Path, props);
Намного более чистый :)
Как другие сказали, массив должен иметь правильный тип для запуска с. Другие ответы показали, как преобразовать подлинный объект [] после факта, но можно создать правильный вид массива для запуска с использования Массива. CreateInstance:
object[] result = (object[]) Array.CreateInstance(type, properties.Length);
Принятие type
ссылочный тип, это должно работать - массив будет иметь корректный тип, но Вы будете использовать его в качестве object[]
только заполнить его.
Это корректно, но это не означает, что можно бросить контейнеры текстового объекта к контейнерам других типов. Объект [] не является тем же самым как Объектом (хотя Вы, странно, могли бросить Объект [] для Возражения).
В основном, нет. Существуют некоторые, ограниченные, использование ковариантности массива, но лучше просто знать, какой тип массива Вы хотите. Существует универсальный Массив. ConvertAll, который достаточно легок (по крайней мере, это легче с C# 3.0):
Property[] props = Array.ConvertAll(source, prop => (Property)prop);
Версия C# 2.0 (идентичный в значении) намного менее благоприятна для глазного яблока:
Property[] props = Array.ConvertAll<object,Property>(
source, delegate(object prop) { return (Property)prop; });
Или просто создайте новое Свойство [] правильного размера и скопируйте вручную (или через Array.Copy
).
Как пример вещей можно сделать с ковариантностью массива:
Property[] props = new Property[2];
props[0] = new Property();
props[1] = new Property();
object[] asObj = (object[])props;
Здесь, "asObj" все еще a Property[]
- это это просто доступный как object[]
. В C# 2.0 и выше, дженерики обычно делают более оптимальный вариант, чем ковариантность массива.
Вы не можете преобразовать массив как этот - он возвращает массив объектов, который отличается от объекта. Попробуйте Массив. ConvertAll
в C# 2.0 вы можете сделать это, используя отражение, без использования generics и без знания нужного типа во время компиляции.
//get the data from the object factory
object[] newDataArray = AppObjectFactory.BuildInstances(Type.GetType("OutputData"));
if (newDataArray != null)
{
SomeComplexObject result = new SomeComplexObject();
//find the source
Type resultTypeRef = result.GetType();
//get a reference to the property
PropertyInfo pi = resultTypeRef.GetProperty("TargetPropertyName");
if (pi != null)
{
//create an array of the correct type with the correct number of items
pi.SetValue(result, Array.CreateInstance(Type.GetType("OutputData"), newDataArray.Length), null);
//copy the data and leverage Array.Copy's built in type casting
Array.Copy(newDataArray, pi.GetValue(result, null) as Array, newDataArray.Length);
}
}
Вы захотите заменить все вызовы Type.GetType("OutputData") и GetProperty("PropertyName") на код, который считывается из файла конфигурации.
Я бы также использовал дженерик, чтобы продиктовать создание SomeComplexObject
T result = new T();
Type resultTypeRef = result.GetType();
Но я сказал, что вам не нужно использовать дженерики.
Никаких гарантий по производительности/эффективности, но это работает.