public T[] GetAttributeAsArray <T>(string attributeName, bool isAttributeRequired, IConstraintChecker <T> constraints, string[] attributeNameAliases,
                                           char[] separatorCharacters)
        {
            // Vector3 are triples, so requires special handling...
            if (typeof(T) == typeof(Vector3))
            {
                return((T[])UtilGetAttributeAsVector3s(attributeName, isAttributeRequired, attributeNameAliases));
            }


            constraints         = constraints ?? new ConstrainTo.Anything <T>();
            separatorCharacters = separatorCharacters ?? new[] { ' ', ',', ';' };

            bool   isError    = false;
            string keyName    = UtilLocateKey(isAttributeRequired, attributeName, attributeNameAliases);
            var    resultList = new List <T>();

            if ((keyName == null) || !Attributes.ContainsKey(keyName))
            {
                resultList.Clear();
                return(resultList.ToArray());
            }

            // We 'continue' even if problems are encountered...
            // By doing this, the profile writer can see all his mistakes at once, rather than being
            // nickel-and-dimed to death with error messages.
            foreach (string listEntry in Attributes[keyName].Split(separatorCharacters, StringSplitOptions.RemoveEmptyEntries))
            {
                T tmpResult;

                try
                { tmpResult = UtilTo <T>(keyName, listEntry); }

                catch (Exception)
                {
                    isError = true;
                    continue;
                }

                string constraintViolationMessage = constraints.Check(keyName, tmpResult);
                if (constraintViolationMessage != null)
                {
                    QBCLog.Error(QBCLog.BuildMessageWithContext(Element, constraintViolationMessage));
                    isError = true;
                    continue;
                }

                resultList.Add(tmpResult);
            }

            if (isError)
            {
                resultList.Clear();
                IsAttributeProblem = true;
            }

            return(resultList.ToArray());
        }
        private object UtilGetAttributeAs <T>(string attributeName, bool isAttributeRequired, IConstraintChecker <T> constraints, string[] attributeNameAliases)
        {
            Type concreteType = typeof(T);

            // Vector3 are a triple of attributes, so requires special handling...
            if (concreteType == typeof(Vector3))
            {
                return(UtilGetXYZAttributesAsVector3(attributeName, isAttributeRequired, attributeNameAliases));
            }


            constraints = constraints ?? new ConstrainTo.Anything <T>();

            string keyName = UtilLocateKey(isAttributeRequired, attributeName, attributeNameAliases);

            if ((keyName == null) || !Attributes.ContainsKey(keyName))
            {
                return(null);
            }

            T      tmpResult;
            string valueAsString = Attributes[keyName];

            try
            { tmpResult = UtilTo <T>(keyName, valueAsString); }
            catch (Exception)
            {
                IsAttributeProblem = true;
                return(null);
            }

            string constraintViolationMessage = constraints.Check(keyName, tmpResult);

            if (constraintViolationMessage != null)
            {
                QBCLog.Error(QBCLog.BuildMessageWithContext(Element, constraintViolationMessage));
                IsAttributeProblem = true;
                return(null);
            }

            return(tmpResult);
        }