//============================================================================ /// <summary> /// Writes the SDML value as XML. /// </summary> /// <param name="attrInfo">The typed value to use.</param> /// <param name="indent">Indent spaces to use. -1 = no indent.</param> /// <param name="tab">Number of spaces in each tab</param> /// <returns>The XML for the SDML value.</returns> //============================================================================ protected override String writeFieldInfo(TTypedValue attrInfo, int indent, int tab) { uint i; int oneIndent; int nextIndent; int startIndent; String CR = ""; //determine how much to indent this description oneIndent = 0; startIndent = 0; if (indent > -1) { oneIndent = tab; startIndent = indent; CR = "\r\n"; } String sIndent = new String(' ', startIndent); //begin at this level nextIndent = indent + oneIndent; StringBuilder xml = new StringBuilder(""); if (attrInfo.baseType() != TTypedValue.TBaseType.ITYPE_DEF) xml.Append(" kind=\"" + attrInfo.typeName() + "\""); if (attrInfo.isArray()) xml.Append(" array=\"T\""); if ((attrInfo.units().Length > 0) && (attrInfo.units()[0] != '-')) xml.Append(" unit=\"" + attrInfo.units() + "\""); xml.Append(">" + CR); if (attrInfo.isScalar()) // Scalars - use a <val> element { xml.Append(sIndent + "<val>" + scalarString(attrInfo) + "</val>" + CR); } else { //now nest into the fields/elements for (i = 1; i <= attrInfo.count(); i++) { if (attrInfo.isArray() && (attrInfo.baseType() != TTypedValue.TBaseType.ITYPE_DEF)) { xml.Append(new String(' ', oneIndent) + "<val>" + scalarString(attrInfo.item(i)) + "</val>" + CR); // Scalar array, indented format } else if (attrInfo.isArray()) // All other arrays xml.Append(sIndent + "<element" + writeFieldInfo(attrInfo.item(i), nextIndent, oneIndent) + sIndent + "</element>" + CR); else if (attrInfo.isRecord()) // Records xml.Append(sIndent + "<field name=\"" + attrInfo.item(i).Name + "\"" + writeFieldInfo(attrInfo.item(i), nextIndent, oneIndent) + sIndent + "</field>" + CR); } } return xml.ToString(); }
//============================================================================ /// <summary> /// Creates a 1-dimensional array of arbitrary type /// baseValue is used as a blue print only. /// </summary> /// <param name="arrayName">Name of the array.</param> /// <param name="baseValue">Blue print typed value.</param> /// <param name="noElements">Number of elements for the array.</param> //============================================================================ public TTypedValue(String arrayName, TTypedValue baseValue, int noElements) { ascii = new System.Text.ASCIIEncoding(); FMembers = new List<TTypedValue>(); //set the kind of this typed value FBaseType = baseValue.FBaseType; parser = null; FData = null; FDataSize = 0; childTemplate = null; FUnit = ""; }
//============================================================================ /// <summary> /// Copies data from one type to this type using the getData() setData() pair. /// Assumes that the source and destination are exactly compatible. Arrays will be /// resized as required. /// </summary> /// <param name="srcValue">The source value.</param> // adapted from A. Moore 2002 //============================================================================ public void copyFrom(TTypedValue srcValue) { if ((srcValue != null)) { uint iSize = srcValue.sizeBytes(); if (iSize > 0) { Byte[] data = new Byte[iSize]; srcValue.getData(ref data); setData(data, (int)iSize, 0); } } }
/// <summary> /// /// </summary> /// <param name="sTagDefinition"></param> /// <param name="aType"></param> protected void defineParameters(string sTagDefinition, TTypedValue.TBaseType aType) { string[] sDefn = new string[0]; int Kdx; Tokenise(sTagDefinition, ref sDefn, "-"); Kdx = FDefinitions.Length; Array.Resize(ref FDefinitions, Kdx + 1); FDefinitions[Kdx] = new TParameterDefinition(sDefn, aType); }
/// <summary> /// /// </summary> /// <param name="aValue"></param> /// <param name="Intake"></param> private void Value2IntakeRecord(TTypedValue aValue, ref GrazType.IntakeRecord Intake) { Intake.Biomass = aValue.item(1).asDouble(); // Item[1]="dm" Intake.Digestibility = aValue.item(2).asDouble(); // Item[2]="dmd" Intake.CrudeProtein = aValue.item(3).asDouble(); // Item[3]="cp_conc" Intake.PhosContent = aValue.item(4).asDouble(); // Item[4]="p_conc" Intake.SulfContent = aValue.item(5).asDouble(); // Item[5]="s_conc" Intake.Degradability = aValue.item(6).asDouble(); // Item[6]="prot_dg" Intake.AshAlkalinity = aValue.item(7).asDouble(); // Item[7]="ashalk" Intake.HeightRatio = aValue.item(8).asDouble(); // Item[8]="height_ratio" }
//============================================================================ /// <summary> /// Gets the typed value as an XML description. <init> </init> /// </summary> /// <param name="value">The typed value to describe as XML.</param> /// <param name="startIndent">Formatting indentation start.</param> /// <param name="tab">Number of spaces in each tab</param> /// <returns>The string buffer with the result.</returns> //============================================================================ public override String getText(TTypedValue value, int startIndent, int tab) { int nextIndent; if (startIndent > -1) nextIndent = startIndent + tab; else nextIndent = -1; if (startIndent < 0) startIndent = 0; String sIndent= new String(' ', startIndent); StringBuilder sbuf = new StringBuilder(sIndent); sbuf.Append("<init name=\""); sbuf.Append(value.Name); sbuf.Append("\""); sbuf.Append(writeFieldInfo(value, nextIndent, tab)); sbuf.Append(sIndent); sbuf.Append("</init>"); return sbuf.ToString(); }
//============================================================================ /// <summary> /// Copy constructor. This constructor makes a copy of the source's structure. /// For specialised child classes, this constructor should be overriden. /// </summary> /// <param name="typedValue">Use this as the blue print type.</param> //============================================================================ public TSDMLValue(TTypedValue typedValue) : base (typedValue) { //required in this derived class initTypeCopy(typedValue); //calls suitable virtual functions }
//============================================================================ /// <summary> /// Return the string for the scalar ttypedvalue. /// Numeric types are returned without any rounding or escaping. /// </summary> /// <param name="attrInfo">The scalar TTypedValue</param> /// <returns>String represenation of the scalar</returns> //============================================================================ protected String scalarString(TTypedValue attrInfo) { String strVal; if ((attrInfo.baseType() >= TTypedValue.TBaseType.ITYPE_SINGLE) && (attrInfo.baseType() <= TTypedValue.TBaseType.ITYPE_DOUBLE)) { strVal = attrInfo.asDouble().ToString(); //full precision } else { if ((attrInfo.baseType() >= TTypedValue.TBaseType.ITYPE_INT1) && (attrInfo.baseType() <= TTypedValue.TBaseType.ITYPE_INT8)) { strVal = attrInfo.asInt().ToString(); //no need to escape this } else { strVal = attrInfo.asEscapedString(); } } return strVal; }
//====================================================================== /// <summary> /// Finds the type of this array object by recursing into the lower dimesions /// if needed. /// </summary> /// <param name="typedValue">The typed value to interogate.</param> /// <returns>The base type for this variable. </returns> // N.Herrmann Apr 2002 //====================================================================== protected TBaseType findArrayType(TTypedValue typedValue) { TTypedValue value; TBaseType baseType; baseType = TBaseType.ITYPE_EMPTY; //default value = typedValue.item(1); //first element if (value != null) { baseType = value.baseType(); if (baseType == TBaseType.ITYPE_EMPTY) baseType = findArrayType(value); } return baseType; }
//====================================================================== /// <summary> /// Assignment from a TTypedValue that need not be of identical type, but must /// be type-compatible. /// When converting from a scalar string to a numeric an exception will be thrown /// if the source string is not a valid numeric. /// </summary> /// <param name="srcValue">The source typed value.</param> /// <returns>True is the value can be set.</returns> //====================================================================== public Boolean setValue(TTypedValue srcValue) { bool result = false; bool bCompatible; if (srcValue != null) { bCompatible = ((FIsScalar == srcValue.isScalar()) && (FIsArray == srcValue.isArray())); if (FBaseType == TBaseType.ITYPE_DEF) { bCompatible = (bCompatible && (srcValue.baseType() == TBaseType.ITYPE_DEF)); } if (!bCompatible) { String error = String.Format("Incompatible assignment from {0} to {1}\nCannot convert {2} to {3}", Name, srcValue.Name, srcValue.baseType().ToString(), FBaseType.ToString()); throw (new TypeMisMatchException(error)); } if (FIsScalar) { try { switch (FBaseType) { case TBaseType.ITYPE_INT1: case TBaseType.ITYPE_INT2: case TBaseType.ITYPE_INT4: { result = setValue(srcValue.asInt()); break; } case TBaseType.ITYPE_INT8: result = setValue(Convert.ToInt64(srcValue.asDouble())); break; case TBaseType.ITYPE_DOUBLE: { result = setValue(srcValue.asDouble()); break; } case TBaseType.ITYPE_SINGLE: { result = setValue(srcValue.asSingle()); break; } case TBaseType.ITYPE_BOOL: { result = setValue(srcValue.asBool()); break; } default: { result = setValue(srcValue.asStr()); break; } } } catch { throw (new Exception("setValue() cannot convert " + srcValue.asStr() + " to " + FBaseType.ToString())); } } else { if (FIsArray) { setElementCount(srcValue.count()); } uint iCount = count(); for (uint Idx = 1; Idx <= iCount; Idx++) { result = item(Idx).setValue(srcValue.item(Idx)); } } } return result; }
//============================================================================ /// <summary> /// For arrays, this will adjust the size of the FMembers list. /// </summary> /// <param name="dim">New dimension of this array.</param> // N.Herrmann Apr 2002 //============================================================================ public void setElementCount(uint dim) { if (FIsArray) { if (dim > FMembers.Count) { //add some more elements while (dim > FMembers.Count) { //add a copy of the first element (structure) if (FMembers.Count > 0) { //if there is an element to clone newMember(item(1)); //Clones (copy constructor) the element structure } else { if (childTemplate != null) { //if previously stored an item that was removed when setElementCount(0) addMember(childTemplate); childTemplate = null; //now belongs to the list } else addScalar("", FBaseType); //else determine what type the first element should be (must be a scalar) } } } else if (dim < FMembers.Count) { while ((dim < FMembers.Count) && (FMembers.Count > 0)) { //delete some elements (newsize>=0) deleteElement(FMembers.Count); //1 based } } } else throw (new TypeMisMatchException("Cannot add or remove an array member to a non-array type.")); }
/// <summary> /// Add a new member. /// </summary> /// <param name="bluePrintValue"></param> public abstract void newMember(TTypedValue bluePrintValue);
/// <summary> /// Text representation of a TTypedValue. /// </summary> /// <param name="value">The value</param> /// <param name="startIndent">Indent from here.</param> /// <param name="tab">Number of spaces in each tab</param> /// <returns>The XML.</returns> public abstract String getText(TTypedValue value, int startIndent, int tab);
//============================================================================ /// <summary> /// Tests for identity of two TTypedValue objects. /// </summary> /// <param name="otherValue">Typed value to test against this one.</param> /// <returns>True if it matches in type, size, and structure.</returns> // N.Herrmann Apr 2002 //============================================================================ public Boolean equals(TTypedValue otherValue) { uint i; Boolean bEqual = false; if ((otherValue != null) && (FBaseType == otherValue.baseType()) && (FIsArray == otherValue.isArray()) && (FIsRecord == otherValue.isRecord()) && (count() == otherValue.count()) && (FDataSize == otherValue.sizeBytes())) bEqual = true; if (bEqual) { if (FIsScalar) bEqual = bEqual && (asStr() == otherValue.asStr()); //str comparison of the scalar (needs refinement) } else { for (i = 1; i <= count(); i++) bEqual = bEqual && item(i).equals(otherValue.item(i)); } return bEqual; }
//============================================================================== /// <summary> /// Delete an element from an array. Assumes that 'index' is the natural order /// of the items in the FMembers list. /// </summary> /// <param name="index">Array index 1->x</param> /// <returns></returns> // N.Herrmann Feb 2003 //============================================================================== public void deleteElement(int index) { if (FIsArray) { if ((FMembers.Count > 0) && (FMembers.Count >= index)) { //delete some elements (newsize>=0) if (FMembers.Count == 1) childTemplate = FMembers[index - 1]; //store the last element locally for cloning later FMembers.RemoveAt(index - 1); //delete it from the list } } }
//============================================================================ /// <summary> /// Copy constructor. This constructor makes a copy of the source's structure. /// For specialised child classes, this constructor should be overriden. /// </summary> /// <param name="typedValue">Use this typed value as the source.</param> // N.Herrmann Apr 2002 //============================================================================ public TTypedValue(TTypedValue typedValue) { ascii = new System.Text.ASCIIEncoding(); FMembers = new List<TTypedValue>(); //set the kind of this typed value FBaseType = typedValue.FBaseType; FData = null; FDataSize = 0; parser = null; //won't be using a parser here childTemplate = null; FUnit = ""; //Called in the derived classes because it calls virtual functions //initTypeCopy(typedValue) }
//============================================================================ /// <summary> /// Only allowed to add members to records and arrays. /// </summary> /// <param name="newMember">The new member to add to this structure.</param> // N.Herrmann Apr 2002 //============================================================================ public void addMember(TTypedValue newMember) { if (((FIsArray || FIsRecord)) && (newMember != null)) { if (FIsArray && ((FBaseType >= TBaseType.ITYPE_INT1) && (FBaseType <= TBaseType.ITYPE_DOUBLE))) //if number type newMember.setUnits(FUnit); FMembers.Add(newMember); } }
//============================================================================ /// <summary> /// The new member to add to this structure. /// </summary> /// <param name="typedValue">Typed value to copy.</param> // N.Herrmann Apr 2002 //============================================================================ protected void initTypeCopy(TTypedValue typedValue) { uint i; Name = typedValue.Name; FBaseType = typedValue.baseType(); FIsScalar = typedValue.isScalar(); FIsArray = typedValue.isArray(); FIsRecord = typedValue.isRecord(); setUnits(typedValue.units()); if (FIsScalar) { createScalar(); switch (FBaseType) { //For scalars, copy the value data. case TBaseType.ITYPE_INT1: //Data pertaining to arrays and records case TBaseType.ITYPE_INT2: // is ultimately stored in their case TBaseType.ITYPE_INT4: // constituent scalars case TBaseType.ITYPE_INT8: setValue(typedValue.asInt()); break; case TBaseType.ITYPE_SINGLE: setValue(typedValue.asSingle()); break; case TBaseType.ITYPE_DOUBLE: setValue(typedValue.asDouble()); break; case TBaseType.ITYPE_BOOL: setValue(typedValue.asBool()); break; case TBaseType.ITYPE_CHAR: case TBaseType.ITYPE_WCHAR: setValue(typedValue.asChar()); break; case TBaseType.ITYPE_STR: case TBaseType.ITYPE_WSTR: setValue(typedValue.asStr()); break; } } else if (FIsArray || FIsRecord) { uint iCount = typedValue.count(); if (FIsArray && (iCount == 0)) { if (typedValue.item(0) != null) newMember(typedValue.item(0)); setElementCount(0); } else for (i = 1; i <= iCount; i++) newMember(typedValue.item(i)); //clones and adds this typed value } }
//============================================================================ /// <summary> /// Creates a one dimensional array of arbitrary items. /// </summary> /// <param name="sArrayName">Name of this array.</param> /// <param name="baseValue">Use as the base type of the array elements.</param> /// <param name="iNoElements">Create it with this number of elements.</param> //============================================================================ public TSDMLValue(String sArrayName, TTypedValue baseValue, int iNoElements) : base (sArrayName, baseValue, iNoElements) { newMember( baseValue ); setElementCount((uint)iNoElements); }
/// <summary> /// Writes a field as a string /// </summary> /// <param name="attrInfo">The value</param> /// <param name="indent">Indentation 0-n</param> /// <param name="tab">Number of spaces in each tab</param> /// <returns>The XML for the typed value.</returns> protected abstract String writeFieldInfo(TTypedValue attrInfo, int indent, int tab);
//============================================================================ /// <summary> /// Uses the copy constructor to make a clone of a typedvalue's structure. /// It is then added as a member to an array or record. /// this virtual function is expected to be overriden so that new members are /// of the child classes' type. /// </summary> /// <param name="bluePrintValue">Use this typed value as the blue print.</param> //============================================================================ public override void newMember(TTypedValue bluePrintValue) { TSDMLValue newElement; newElement = new TSDMLValue(bluePrintValue); //calls copy constructor addMember(newElement); //add the copy }
//============================================================================ /// <summary> /// Constructor that will show details of the two types causing the problem. /// </summary> /// <param name="first">First TTypedValue.</param> /// <param name="second">Second TTypedValue.</param> //============================================================================ public TypeMisMatchException(TTypedValue first, TTypedValue second) : base("Type mismatch exception: " + first.typeName() + " does not match " + second.typeName()) { }
//============================================================================ /// <summary> /// Construct this object using the parser already created in the parent. Also /// use the dom node, baseNode to be the root node of the document for this /// new typed value. Can also specify the base type using sBaseType. /// </summary> /// <param name="parentParser">Pointer to the parents parser.</param> /// <param name="baseNode">DOM node to use as the root node.</param> /// <param name="sBaseType">Used to set the base type. See <see cref="sTYPECODES"/></param> // N.Herrmann Apr 2002 //============================================================================ public TTypedValue(TSDMLParser parentParser, XmlNode baseNode, String sBaseType) { ascii = new System.Text.ASCIIEncoding(); FMembers = new List<TTypedValue>(); //set the kind of this typed value setBaseType(sBaseType); parser = null; FData = null; FDataSize = 0; childTemplate = null; FUnit = ""; //Called in the derived classes because it calls virtual functions //buildType(parentParser, baseNode); }
//============================================================================ /// <summary> /// Creates a scalar of this aBaseType with sName. /// </summary> /// <param name="sName">Name of the scalar.</param> /// <param name="aBaseType">Base type of this scalar.</param> // N.Herrmann Apr 2002 //============================================================================ public TTypedValue(String sName, TBaseType aBaseType) { ascii = new System.Text.ASCIIEncoding(); FMembers = new List<TTypedValue>(); //set the kind of this typed value FBaseType = aBaseType; //Called in the derived classes because it calls virtual functions //constructScalar(szName, iBaseType); //create a scalar type of TTypedValue parser = null; childTemplate = null; FUnit = ""; }
/// <summary> /// /// </summary> /// <param name="aValue"></param> /// <returns></returns> private GrazType.TGrazingInputs Value2GrazingInputs(TTypedValue aValue) { double fTotalDM; int Idx; GrazType.TGrazingInputs Result = new GrazType.TGrazingInputs(); GrazType.zeroGrazingInputs(ref Result); for (Idx = 1; Idx <= Math.Min(GrazType.DigClassNo, aValue.item(1).count()); Idx++) // Item[1]="herbage" Value2IntakeRecord(aValue.item(1).item((uint)Idx), ref Result.Herbage[Idx]); fTotalDM = 0.0; for (Idx = 1; Idx <= GrazType.DigClassNo; Idx++) fTotalDM = fTotalDM + Result.Herbage[Idx].Biomass; Result.TotalGreen = fTotalDM * aValue.item(2).asDouble(); // Item[2]="propn_green" Result.TotalDead = fTotalDM - Result.TotalGreen; Result.LegumePropn = aValue.item(3).asDouble(); // Item[3]="legume" Result.SelectFactor = aValue.item(4).asDouble(); // Item[4]="select_factor" for (Idx = 1; Idx <= Math.Min(2, aValue.item(5).count()); Idx++) // Item[5]="seed" { Value2IntakeRecord(aValue.item(5).item((uint)Idx), ref Result.Seeds[1, Idx]); Result.SeedClass[1, Idx] = aValue.item(6).item((uint)Idx).asInteger(); // Item[6]="seed_class" } return Result; }
//============================================================================ /// <summary> /// Creates a one dimensional array of scalar items. /// </summary> /// <param name="sArrayName">Name of this array.</param> /// <param name="aBaseType">Set the base type of this array.</param> /// <param name="iNoElements">Create it with this number of elements.</param> // N.Herrmann Apr 2002 //============================================================================ public TTypedValue(String sArrayName, TBaseType aBaseType, int iNoElements) { ascii = new System.Text.ASCIIEncoding(); FMembers = new List<TTypedValue>(); //set the kind of this typed value FBaseType = aBaseType; parser = null; FData = null; FDataSize = 0; childTemplate = null; Name = sArrayName; FUnit = ""; FIsScalar = false; FIsArray = true; FIsRecord = false; //Called in the derived classes because they call virtual functions //addScalar("", iBaseType); //calls suitable virtual function //setElementCount(iNoElements); }
/// <summary> /// Each element of a "definition string" array may take one of two forms: /// * val:val Integer subrange (e.g. "1:8") /// * text[;text]* List of text indices /// /// For example, if the original string from which sDefnStrings was constructed /// was "KQ-1:4-leaf;stem", then the resulting tree of definitions would be: /// KQ /// | /// +-+-------------+-------------+-------------+ /// | | | | /// 1 2 3 4 /// +-+-----+ +-+-----+ +-+-----+ +-+-----+ /// | | | | | | | | /// leaf stem leaf stem leaf stem leaf stem /// </summary> /// <param name="sDefnStrings"></param> /// <param name="aType"></param> /// <param name="iOffset"></param> public TParameterDefinition(string[] sDefnStrings, TTypedValue.TBaseType aType, int iOffset = 0) { FItems = new TParameterDefinition[0]; string[] sSubDefnStrings = new string[0]; string sIndexStr; int iPosn; int Idx; FName = sDefnStrings[0]; for (Idx = 1; Idx <= iOffset; Idx++) FName = FName + "-" + sDefnStrings[Idx]; if (iOffset < (sDefnStrings.Length - 1)) FName = FName + "-"; FName = FName.ToLower(); FNamePart = sDefnStrings[iOffset].ToLower(); FType = aType; FDefined = false; if (iOffset < (sDefnStrings.Length - 1)) { Array.Resize(ref sSubDefnStrings, sDefnStrings.Length); for (Idx = 0; Idx <= (sSubDefnStrings.Length - 1); Idx++) sSubDefnStrings[Idx] = sDefnStrings[Idx]; sIndexStr = sDefnStrings[iOffset + 1]; iPosn = sIndexStr.IndexOf(':'); if (iPosn >= 0) // Integer subrange { int start = Convert.ToInt32(sIndexStr.Substring(0, iPosn)); int endpos = Convert.ToInt32(sIndexStr.Substring(iPosn + 1, sIndexStr.Length - iPosn - 1)); for (Idx = start; Idx <= endpos; Idx++) { sSubDefnStrings[iOffset + 1] = Convert.ToString(Idx); Array.Resize(ref FItems, FItems.Length + 1); FItems[FItems.Length - 1] = new TParameterDefinition(sSubDefnStrings, aType, iOffset + 1); } } else // Single index or semi-colon-separated } { // list of indices } while (sIndexStr != "") { iPosn = sIndexStr.IndexOf(";"); if (iPosn >= 0) { sSubDefnStrings[iOffset + 1] = sIndexStr.Substring(0, iPosn); sIndexStr = sIndexStr.Substring(iPosn + 1, sIndexStr.Length - iPosn - 1); } else { sSubDefnStrings[iOffset + 1] = sIndexStr; sIndexStr = ""; } Array.Resize(ref FItems, FItems.Length + 1); FItems[FItems.Length - 1] = new TParameterDefinition(sSubDefnStrings, aType, iOffset + 1); } } } FCount = FItems.Length; if (bIsScalar()) FParamCount = 1; else FParamCount = FCount * item(0).iParamCount; }
//============================================================================ /// <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; }