private AFAttributeList CreateBrandNewInputList(object context) { // PRO TIP: // See comments in GetInputs where you want to avoid _cachedInputAttrs.Add or AddRange. // For thread safety, use a brand new list that is local to this method. // Start with a brand new list var brandNewList = new AFAttributeList(); AFAttribute measurement = null; // First and foremost we need a measurement attribute, which is the centerpoint to compare against limits. if (UseParentAttribute) { // https://techsupport.osisoft.com/Documentation/PI-AF-SDK/html/P_OSIsoft_AF_Asset_AFDataReference_Attribute.htm // https://techsupport.osisoft.com/Documentation/PI-AF-SDK/html/P_OSIsoft_AF_Asset_AFAttribute_Parent.htm measurement = Attribute.Parent; if (measurement == null) { throw new Exception("Root-level attribute does not have a parent. You must define 'MeasAttr=something' in the ConfigString."); } } else { // Let's offer some bit of name substitution. // However, the GetInputs method lacks any timeContext, which restricts @value substitution // to current values only. This restriction is fine for static attributes. // https://techsupport.osisoft.com/Documentation/PI-AF-SDK/html/T_OSIsoft_AF_AFNameSubstitutionType.htm var path = SubstituteParameters(_measAttrName, this, context, timeContext: null); // Note that the final fetch of the measurement attribute is *relative* to the current Attribute. // https://techsupport.osisoft.com/Documentation/PI-AF-SDK/html/P_OSIsoft_AF_Asset_AFAttribute_Attributes.htm measurement = Attribute.Attributes[path]; if (measurement == null) { throw new Exception($"MeasAttr '{_measAttrName}' not found. Check your ConfigString."); } } if (!IsNumericType(Type.GetTypeCode(measurement.Type))) { throw new Exception($"MeasAttr does not have a numeric Type."); } // If the list will have any items, the measurement will always be at Index 0. brandNewList.Add(measurement); // Let the CDR automatically fetch the associated limits. // These could come back in any order, plus some or all may be missing! // Geez, doesn't that make it fun and challenging! // https://techsupport.osisoft.com/Documentation/PI-AF-SDK/html/M_OSIsoft_AF_Asset_AFAttribute_GetAttributesByTrait.htm brandNewList.AddRange(measurement.GetAttributesByTrait(AllowedTraits)); return(brandNewList); }