//============================================================================ /// <summary> /// Recursive routine for checking whether two types are (a) identical, /// (b) different but compatible, (c) incompatible. /// <para>Note:</para> /// <para>1. Type compatibility is not a transitive relationship.</para> /// <para>2. Unit compatibility needs further implementation.</para> /// </summary> /// <param name="srcValue">The TTypedValue to compare with.</param> /// <returns>Returns: 0 - exact match, 1 - compatible, -1 - cannot match</returns> //============================================================================ public int canAssignFrom(TTypedValue srcValue) { int result = ctBAD; uint Idx; if (srcValue.isScalar()) { if (!FIsScalar) result = ctBAD; else if (srcValue.baseType() == FBaseType) result = ctSAME; else if ((srcValue.baseType() <= TBaseType.ITYPE_INT8) && (srcValue.baseType() >= TBaseType.ITYPE_INT1) && (FBaseType <= TBaseType.ITYPE_INT8) && (FBaseType >= TBaseType.ITYPE_INT1)) result = ctCOMP; //both integers else if ((FBaseType >= TBaseType.ITYPE_SINGLE) && (FBaseType <= TBaseType.ITYPE_DOUBLE) && //These conditions are not transitive (srcValue.baseType() >= TBaseType.ITYPE_INT1) && (srcValue.baseType() <= TBaseType.ITYPE_DOUBLE)) result = ctCOMP; //can match an int/single source to single/double destination else if ((srcValue.baseType() == TBaseType.ITYPE_CHAR) && ((FBaseType == TBaseType.ITYPE_WCHAR) || (FBaseType == TBaseType.ITYPE_STR) || (FBaseType == TBaseType.ITYPE_WSTR))) result = ctCOMP; else if ((srcValue.baseType() == TBaseType.ITYPE_WCHAR) && (FBaseType == TBaseType.ITYPE_WSTR)) result = ctCOMP; else if ((srcValue.baseType() == TBaseType.ITYPE_STR) && (FBaseType == TBaseType.ITYPE_WSTR)) result = ctCOMP; // A sop to the old APSIM manager, which sends out all request-set values as strings else if ((srcValue.baseType() == TBaseType.ITYPE_STR) || (FBaseType == TBaseType.ITYPE_WSTR)) result = ctDODGY; else result = ctBAD; if ((FBaseType >= TBaseType.ITYPE_INT1) && (FBaseType <= TBaseType.ITYPE_DOUBLE) && (!unitsMatch(units(), srcValue.units()))) result = ctBAD; } else if (srcValue.isArray()) { //an array if (!FIsArray) result = ctBAD; else { if (count() == 0) setElementCount(1); //addElement(); if (srcValue.count() == 0) srcValue.setElementCount(1); //addElement(); result = member(1).canAssignFrom(srcValue.member(1)); } } else { //a record if (!isRecord()) result = ctBAD; else { uint iCount = count(); result = ctCOMP; // First, test for identity if (iCount == srcValue.count()) { result = ctSAME; for (Idx = 1; Idx <= iCount; Idx++) { if ((member(Idx).Name.ToLower() != srcValue.member(Idx).Name.ToLower()) || (member(Idx).canAssignFrom(srcValue.member(Idx)) != ctSAME)) result = ctCOMP; } } if (result == ctCOMP) { //If not same, test for compatibility String elemName; for (Idx = 1; Idx <= srcValue.count(); Idx++) { elemName = srcValue.member(Idx).Name; //field name if (!hasField(elemName) || (member(elemName).canAssignFrom(srcValue.member(Idx)) == ctBAD)) result = ctBAD; } } } } return result; }