/// <summary>
        /// Set the value of the input field or property using the element.  This function will examine the inputs to determine the 
        /// best match for the element.  In some cases this may trigger a recursive examination of the element's children.
        /// </summary>
        /// <param name="fieldOrProperty">Field or property whose value will be set.</param>
        /// <param name="element">Element to obtain the value from.</param>
        /// <param name="o">Object instance whose field or property will be set.</param>
        void _SetFieldOrProperty(IFieldOrProperty fieldOrProperty, XmlNode element, ref object o)
        {
            // first check for valueOf
            object value = _CheckValueOf(element);

            if (value != null)
            {
                fieldOrProperty.SetValue(o, value);
                // done
                return;
            }

            // check for aggregate
            if (_CheckAggregate(fieldOrProperty, element, ref o))
                // no need to set value; values of aggregates are set as post process action.
                return;

            string objName = _GetObjectName(o);

            // if its a string we can just set it
            if (fieldOrProperty.DeclaredType == typeof(System.String))
            {
                fieldOrProperty.SetValue(o, element.InnerText);
            }
            else if (TypeUtil.IsPrimitiveType(fieldOrProperty.DeclaredType))
            {
                if (element.InnerText == null || element.InnerText.Trim() == string.Empty)
                {
                    _Error("Empty primitive value for type, won't set it: element: " + element.LocalName + ", type: " + fieldOrProperty.DeclaredType.FullName + ", object: " + objName);
                }
                else
                {
                    // extract primitive value and set it
                    try
                    {
                        fieldOrProperty.SetValue(o, TypeUtil.GetPrimitiveValue(fieldOrProperty.DeclaredType, element.InnerText));
                    }
                    catch (Exception)
                    {
                        _Error("TorqueXmlDeserializer._SetFieldOrProperty - Unable to parse format string {0} for type {1} for element {2} in object {3}.", element.InnerText, fieldOrProperty.DeclaredType.FullName, element.LocalName, objName);
                    }
                }
            }
            // if it is a reference type, we can deserialize in to it
            else if (fieldOrProperty.DeclaredType.IsClass || fieldOrProperty.DeclaredType.IsInterface || fieldOrProperty.DeclaredType.IsAbstract)
            {
                bool isInstantiable = !(fieldOrProperty.DeclaredType.IsInterface || fieldOrProperty.DeclaredType.IsAbstract);

                object subObj;
                TypeInfo subType;

                // check for name ref
                if (_BindNameRef(element, fieldOrProperty, ref o) != null)
                    // done with this field
                    return;

                // for reference types, allow deserializing into the existing object, if the attribute is present
                // and there is a valid object.
                subObj = fieldOrProperty.GetValue(o);
                bool inPlace = false;
                if (subObj != null)
                {
                    // instance exists, check for attribute - use the property/field type for this, not
                    // declared type.
                    object[] attributes = fieldOrProperty.GetCustomAttributes(true);
                    foreach (object attr in attributes)
                        if (attr is TorqueXmlDeserializeInPlace)
                        {
                            inPlace = true;
                            break;
                        }

                    if (!inPlace)
                    {
                        // check for xml attribute
                        XmlNode inPlaceAttribute = element.Attributes.GetNamedItem("inPlace");
                        if (inPlaceAttribute != null && Boolean.Parse(inPlaceAttribute.Value))
                            inPlace = true;
                    }
                }

                if (subObj != null && inPlace)
                {
                    // ok to deserialize in place; get the typeinfo object for later use.
                    subType = TypeUtil.FindTypeInfo(subObj.GetType().FullName);
                }
                else
                {
                    // log if we are replacing, but there was an instance already
                    //if (subObj != null)
                    //    _Info("Field has object instance but TorqueXmlDeserializeInPlace/inPlace attribute not specified: creating new object:" + element.LocalName);

                    // in case we are making a fixed size list, pass the number of children down to the object maker
                    int childCount = element.ChildNodes.Count;

                    // if type is not instantiable, we might be able to come up with an instantiable type by looking for type mappings
                    if (!isInstantiable)
                        _MakeNewObject(element, out subObj, out subType, childCount);
                    else
                        // instantiable type, so make object used declared type
                        _MakeNewObject(fieldOrProperty.DeclaredType.FullName, out subObj, out subType, childCount);

                    if (subObj == null)
                    {
                        _Error("Unable to create new instance for element {0} on object {1}", element.LocalName, objName);
                        return;
                    }
                }

                // if it is a list of objects, handle it specially
                if (subType.IsList)
                {
                    DeserializedList dlist = new DeserializedList(subObj);
                    _RecurseList(element, ref dlist, subType);
                }
                else
                    _Recurse(element, ref subObj, subType);

                // set value
                // it is important to do this after the element has been deserialized - some property accessors
                // assume this (such as lists of link points and object types).
                fieldOrProperty.SetValue(o, subObj);
            }
            // if it is a value type, then it must be a struct (because we handled primitives earlier)
            else if (fieldOrProperty.DeclaredType.IsValueType)
            {
                // look for object type ref
                if (_BindObjectTypeRef(element, fieldOrProperty, ref o) != null)
                    return;

                object subObj;
                TypeInfo subType;
                _MakeNewObject(fieldOrProperty.DeclaredType.FullName, out subObj, out subType);
                if (subType == null) // check type for null instead of object, since this is a value type
                {
                    _Error("Unable to create new instance for element {0} on object {1}", element.LocalName, objName);
                    return;
                }

                _Recurse(element, ref subObj, subType);

                // set value
                fieldOrProperty.SetValue(o, subObj);
            }
            else
                _Error("Don't know how to set field or property of type {0} for element {1} on object: {2}", fieldOrProperty.DeclaredType.FullName, element.LocalName, objName);
        }
        /// <summary>
        /// Examine the children of the specifid list element and add its values to the input list.
        /// </summary>
        /// <param name="element">Element to examine</param>
        /// <param name="list">List that will receive the values</param>
        /// <param name="ti">TypeInfo of the list that is receiving the values.</param>
        void _RecurseList(XmlNode element, ref DeserializedList list, TypeInfo ti)
        {
            // get the type of the list.  if it is a specific type (i.e., not "object"), we can use that type
            // to create instances for children that do not specify a type attribute.
            Type listType = list.GetListType();
            bool listTypeInstantiable = TypeUtil.IsInstantiable(listType);

            foreach (XmlNode child in element.ChildNodes)
            {
                if (child.NodeType != XmlNodeType.Element)
                    continue;

                TypeInfo subType = null;
                object subObj = null;

                // does the element have inPlace specified?  If so, search for an existing instance of the same type
                // in the list.  if it exists, deserialize into that instance, instead of into a new object,
                bool inPlace = false;
                XmlNode inPlaceAttribute = child.Attributes.GetNamedItem("inPlace");

                if (inPlaceAttribute != null && Boolean.Parse(inPlaceAttribute.Value))
                {
                    // has attribute.  lookup the type
                    string typeName = _GetObjectTypeName(child);
                    subType = TypeUtil.FindTypeInfo(typeName);
                    // try to find an instance of the type in the list (will be null if unsuccessful)
                    subObj = list.GetFirstInstanceOfType(subType);
                    inPlace = subObj != null;
                }

                if (!inPlace)
                    // create new object
                    _MakeNewObject(child, out subObj, out subType);

                if (subObj == null && subType == null && listTypeInstantiable)
                {
                    // couldn't find a mapping for this type, but the list itself has an instantiable type that we could use.
                    // if we are creating a String, just use the text value from the xml instead of creating a new object.
                    // we can't actual create a new object anyway because String has no zero argument constructor.
                    if (listType == typeof(String))
                    {
                        subObj = child.InnerText;
                        subType = TypeUtil.FindTypeInfo(typeof(String).FullName);
                    }
                    else
                    {
                        // create the new object using the list's type.
                        // sometimes a warning but sometimes what the user intends.  we'll call it _Info
                        // ok, this is just excessive console spam.  don't worry about this case.
                        //_Info("List subelement '{0}' has no default type mapping or type attribute specified.  Using the type of the list container, '{1}', to create list element instance.", child.LocalName, listType.FullName);
                        _MakeNewObject(listType.FullName, out subObj, out subType);
                    }
                }

                // still no object? warn about it and continue
                if (subObj == null)
                {
                    _Warn("Ignoring List subelement '{0}': no default type mapping, no type attribute, and list type '{1}' is not instantiable", child.LocalName, listType.FullName);
                    continue;
                }

                // if the subType is a primitive or enum, do not recurse on it - instead just set the value directly
                if (TypeUtil.IsPrimitiveType(subType.Type))
                {
                    try
                    {
                        subObj = TypeUtil.GetPrimitiveValue(subType.Type, child.InnerText);
                    }
                    catch (Exception)
                    {
                        _Error("TorqueXmlDeserializer._SetFieldOrProperty - Unable to parse format string {0} for type {1}.", child.InnerText, subType.Type.FullName);
                    }
                }
                else
                {
                    _Recurse(child, ref subObj, subType);
                }

                if (!inPlace)
                    list.Add(subObj);
            }
        }