using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace IACommService4CSharp { public static class DType { public const UInt32 Undefined = 0u; /* undefined type */ public const UInt32 Boolean = 1u; /* boolean */ public const UInt32 SByte = 2u; /* signed byte */ public const UInt32 Byte = 3u; /* unsigned byte */ public const UInt32 Int16 = 4u; /* signed 16 bit integer */ public const UInt32 UInt16 = 5u; /* unsigned 16 bit integer */ public const UInt32 Int32 = 6u; /* signed 32 bit integer */ public const UInt32 UInt32 = 7u; /* unsigned 32 bit integer */ public const UInt32 Int64 = 8u; /* signed 64 bit integer */ public const UInt32 UInt64 = 9u; /* unsigned 64 bit integer */ public const UInt32 Float = 10u; /* 32 bit single precision floating point */ public const UInt32 Double = 11u; /* 64 bit double precision floating point */ public const UInt32 String = 12u; /* UTF-8 string */ public const UInt32 Complex = 100u; /* complex type, such as Structure */ public const UInt32 Custom = 200u; /* custom type */ }; public class DataValue_t : IDisposable { private static Dictionary m_dataTypeDic = new Dictionary() { { DType.Boolean, typeof(bool) }, { DType.SByte, typeof(sbyte) }, { DType.Byte, typeof(byte) }, { DType.Int16, typeof(short) }, { DType.UInt16, typeof(ushort) }, { DType.Int32, typeof(int) }, { DType.UInt32, typeof(uint) }, { DType.Int64, typeof(long) }, { DType.UInt64, typeof(ulong) }, { DType.Float, typeof(float) }, { DType.Double, typeof(double) }, { DType.String, typeof(string) }, { DType.Custom, typeof(sbyte[]) }, { DType.Undefined, null } }; private IDataValue4CSharp m_value; private bool m_disposed = false; private bool m_isReference = false; public DataValue_t(uint dataType = DType.Undefined, uint[] dimensions = null) { m_value = DataValueFactory4CSharp.Create(dataType, dimensions); if (m_value is null) throw new IACommServiceException(ErrorCode.InvalidArgument); } public DataValue_t(object value) { if (value is null) throw new IACommServiceException(ErrorCode.InvalidArgument); if (value is DataValue_t) { m_value = DataValueFactory4CSharp.Create(DType.Undefined, null); if (m_value is null) throw new IACommServiceException(ErrorCode.InternalError); CopyFrom((DataValue_t)value); return; } Type valueType = value.GetType(); uint[] dimensions = null; if (value is Array) { var arrayValue = value as Array; dimensions = new uint[arrayValue.Rank]; for (int index = 0; index < arrayValue.Rank; index++) { dimensions[index] = (uint)arrayValue.GetLength(index); } valueType = valueType.GetElementType(); } uint dataType = DType.Undefined; if (m_dataTypeDic.ContainsValue(valueType)) { dataType = m_dataTypeDic.First(q => q.Value == valueType).Key; } else if (valueType.IsValueType && !valueType.IsPrimitive && !valueType.IsEnum) { dataType = DType.Complex; } else if (valueType.IsEnum) { dataType = DType.Int16; } else { throw new IACommServiceException(ErrorCode.InvalidArgument); } m_value = DataValueFactory4CSharp.Create(dataType, dimensions); Value = value; } //Internal use public DataValue_t(IDataValue4CSharp value) { m_value = value; if (null == m_value) throw new IACommServiceException(ErrorCode.InvalidArgument); m_isReference = true; } ~DataValue_t() { Dispose(false); } public uint CopyFrom(DataValue_t value) { if(value is null) return ErrorCode.InvalidArgument; return m_value.CopyFrom(value.m_value); } public uint CopyTo(ref DataValue_t value) { if (value is null) value = new DataValue_t(); return m_value.CopyTo(value.m_value); } public uint GetArrayValue(ref uint[] value) { return m_value.GetArrayValue(ref value); } public uint GetArrayValue(ref long[] value) { return m_value.GetArrayValue(ref value); } public uint GetArrayValue(ref ulong[] value) { return m_value.GetArrayValue(ref value); } public uint GetArrayValue(ref bool[] value) { return m_value.GetArrayValue(ref value); } public uint GetArrayValue(ref sbyte[] value) { return m_value.GetArrayValue(ref value); } public uint GetArrayValue(ref byte[] value) { return m_value.GetArrayValue(ref value); } public uint GetArrayValue(ref short[] value) { return m_value.GetArrayValue(ref value); } public uint GetArrayValue(ref ushort[] value) { return m_value.GetArrayValue(ref value); } public uint GetArrayValue(ref int[] value) { return m_value.GetArrayValue(ref value); } public uint GetArrayValue(ref float[] value) { return m_value.GetArrayValue(ref value); } public uint GetArrayValue(ref string[] value) { return m_value.GetArrayValue(ref value); } public uint GetArrayValue(ref double[] value) { return m_value.GetArrayValue(ref value); } public uint GetElement(uint[] indexes, ref DataValue_t value) { if (value is null) value = new DataValue_t(); return m_value.GetElement(indexes, value.m_value); } public uint GetElement(uint index, ref DataValue_t value) { if (value is null) value = new DataValue_t(); return m_value.GetElement(index, value.m_value); } public uint GetValue(ref bool value) { return m_value.GetValue(ref value); } public uint GetValue(ref sbyte value) { return m_value.GetValue(ref value); } public uint GetValue(ref byte value) { return m_value.GetValue(ref value); } public uint GetValue(ref short value) { return m_value.GetValue(ref value); } public uint GetValue(ref uint value) { return m_value.GetValue(ref value); } public uint GetValue(ref int value) { return m_value.GetValue(ref value); } public uint GetValue(ref long value) { return m_value.GetValue(ref value); } public uint GetValue(ref ulong value) { return m_value.GetValue(ref value); } public uint GetValue(ref float value) { return m_value.GetValue(ref value); } public uint GetValue(ref double value) { return m_value.GetValue(ref value); } public uint GetValue(ref string value) { return m_value.GetValue(ref value); } public uint GetValue(ref sbyte[] value) { return m_value.GetValue(ref value); } public uint GetValue(string field, ref DataValue_t value) { if (value is null) value = new DataValue_t(); return m_value.GetValue(field, value.m_value); } public uint GetValue(ref ushort value) { return m_value.GetValue(ref value); } public uint Reset(uint dataType = DType.Undefined, uint[] dimensions = null) { return m_value.Reset(dataType, dimensions); } public uint SetArrayValue(byte[] value) { return m_value.SetArrayValue(value); } public uint SetArrayValue(bool[] value) { return m_value.SetArrayValue(value); } public uint SetArrayValue(sbyte[] value) { return m_value.SetArrayValue(value); } public uint SetArrayValue(short[] value) { return m_value.SetArrayValue(value); } public uint SetArrayValue(float[] value) { return m_value.SetArrayValue(value); } public uint SetArrayValue(int[] value) { return m_value.SetArrayValue(value); } public uint SetArrayValue(uint[] value) { return m_value.SetArrayValue(value); } public uint SetArrayValue(long[] value) { return m_value.SetArrayValue(value); } public uint SetArrayValue(ulong[] value) { return m_value.SetArrayValue(value); } public uint SetArrayValue(double[] value) { return m_value.SetArrayValue(value); } public uint SetArrayValue(string[] value) { return m_value.SetArrayValue(value); } public uint SetArrayValue(ushort[] value) { return m_value.SetArrayValue(value); } public uint SetElement(uint index, DataValue_t value) { if (value is null) return ErrorCode.InvalidArgument; return m_value.SetElement(index, value.m_value); } public uint SetElement(uint[] indexes, DataValue_t value) { if (value is null) return ErrorCode.InvalidArgument; return m_value.SetElement(indexes, value.m_value); } public uint SetValue(string field, DataValue_t value) { if (value is null) return ErrorCode.InvalidArgument; return m_value.SetValue(field, value.m_value); } public uint SetValue(sbyte[] value) { return m_value.SetValue(value); } public uint SetValue(ulong value) { return m_value.SetValue(value); } public uint SetValue(long value) { return m_value.SetValue(value); } public uint SetValue(uint value) { return m_value.SetValue(value); } public uint SetValue(short value) { return m_value.SetValue(value); } public uint SetValue(ushort value) { return m_value.SetValue(value); } public uint SetValue(byte value) { return m_value.SetValue(value); } public uint SetValue(sbyte value) { return m_value.SetValue(value); } public uint SetValue(bool value) { return m_value.SetValue(value); } public uint SetValue(string value) { return m_value.SetValue(value); } public uint SetValue(double value) { return m_value.SetValue(value); } public uint SetValue(int value) { return m_value.SetValue(value); } public uint SetValue(float value) { return m_value.SetValue(value); } public object Get(Type valueType = null) { if (valueType is null && DataType == DType.Complex) { throw new IACommServiceException(ErrorCode.InvalidArgument); } if (valueType != null) { if (valueType == typeof(DataValue_t) || valueType.IsSubclassOf(typeof(DataValue_t))) { object value = null; if (valueType.Name == typeof(ArrayBase_t<>).Name) { if (!IsArray) throw new IACommServiceException(ErrorCode.DataTypeMismatch); value = Activator.CreateInstance(valueType, new object[] { new uint[] { 0 } }); } else if (valueType.IsSubclassOf(typeof(ComplexBase_t))) { if (DataType != DType.Complex) throw new IACommServiceException(ErrorCode.DataTypeMismatch); value = Activator.CreateInstance(valueType); } else { value = Activator.CreateInstance(valueType, new object[] { DType.Undefined, null }); } ((DataValue_t)value).CopyFrom(this); return value; } if (IsArray) { if (!valueType.IsArray || valueType.GetArrayRank() != Dimensions.Length) throw new IACommServiceException(ErrorCode.DataTypeMismatch); valueType = valueType.GetElementType(); } if (valueType.IsEnum) { if (DataType != DType.Int16) throw new IACommServiceException(ErrorCode.DataTypeMismatch); } else if (valueType.IsValueType && !valueType.IsPrimitive) { if (DataType != DType.Complex) throw new IACommServiceException(ErrorCode.DataTypeMismatch); } else if (DataType == DType.Complex || m_dataTypeDic[DataType] != valueType) { throw new IACommServiceException(ErrorCode.DataTypeMismatch); } } if (IsArray) { int[] tempDimensions = Array.ConvertAll(Dimensions, z => (int)z); Array arrayValue = null; switch (DataType) { case DType.Boolean: { bool[] tempArray = null; GetArrayValue(ref tempArray); Convert2MultiDimensionsArray(tempArray, tempDimensions, ref arrayValue); break; } case DType.SByte: { sbyte[] tempArray = null; GetArrayValue(ref tempArray); Convert2MultiDimensionsArray(tempArray, tempDimensions, ref arrayValue); break; } case DType.Byte: { byte[] tempArray = null; GetArrayValue(ref tempArray); Convert2MultiDimensionsArray(tempArray, tempDimensions, ref arrayValue); break; } case DType.Int16: { short[] tempArray = null; GetArrayValue(ref tempArray); if (valueType != null && valueType.IsEnum) { arrayValue = Array.CreateInstance(valueType, tempDimensions); for (int index = 0; index < tempArray.Length; index++) { int[] indexes = null; ConvertIndex(index, tempDimensions, ref indexes); arrayValue.SetValue(Enum.ToObject(valueType, tempArray[index]), indexes); } } else { Convert2MultiDimensionsArray(tempArray, tempDimensions, ref arrayValue); } break; } case DType.UInt16: { ushort[] tempArray = null; GetArrayValue(ref tempArray); Convert2MultiDimensionsArray(tempArray, tempDimensions, ref arrayValue); break; } case DType.Int32: { int[] tempArray = null; GetArrayValue(ref tempArray); Convert2MultiDimensionsArray(tempArray, tempDimensions, ref arrayValue); break; } case DType.UInt32: { uint[] tempArray = null; GetArrayValue(ref tempArray); Convert2MultiDimensionsArray(tempArray, tempDimensions, ref arrayValue); break; } case DType.Int64: { long[] tempArray = null; GetArrayValue(ref tempArray); Convert2MultiDimensionsArray(tempArray, tempDimensions, ref arrayValue); break; } case DType.UInt64: { ulong[] tempArray = null; GetArrayValue(ref tempArray); Convert2MultiDimensionsArray(tempArray, tempDimensions, ref arrayValue); break; } case DType.Float: { float[] tempArray = null; GetArrayValue(ref tempArray); Convert2MultiDimensionsArray(tempArray, tempDimensions, ref arrayValue); break; } case DType.Double: { double[] tempArray = null; GetArrayValue(ref tempArray); Convert2MultiDimensionsArray(tempArray, tempDimensions, ref arrayValue); break; } case DType.String: { string[] tempArray = null; GetArrayValue(ref tempArray); Convert2MultiDimensionsArray(tempArray, tempDimensions, ref arrayValue); break; } case DType.Complex: { arrayValue = Array.CreateInstance(valueType, tempDimensions); DataValue_t elementValue = new DataValue_t(); for (uint index = 0; index < ArraySize; index++) { if (GetElement(index, ref elementValue) != ErrorCode.Good) { elementValue.Dispose(); throw new IACommServiceException(ErrorCode.InternalError); } var element = Convert2Struct(elementValue, valueType); if (element is null) { elementValue.Dispose(); throw new IACommServiceException(ErrorCode.InvalidArgument); } int[] indexes = null; ConvertIndex((int)index, tempDimensions, ref indexes); arrayValue.SetValue(element, indexes); } elementValue.Dispose(); break; } default: { return null; } } return arrayValue; } else { switch (DataType) { case DType.Boolean: { bool value = false; GetValue(ref value); return value; } case DType.SByte: { sbyte value = 0; GetValue(ref value); return value; } case DType.Byte: { byte value = 0; GetValue(ref value); return value; } case DType.Int16: { short value = 0; GetValue(ref value); if (valueType != null && valueType.IsEnum) { return Enum.ToObject(valueType, value); } else { return value; } } case DType.UInt16: { ushort value = 0; GetValue(ref value); return value; } case DType.Int32: { int value = 0; GetValue(ref value); return value; } case DType.UInt32: { uint value = 0; GetValue(ref value); return value; } case DType.Int64: { long value = 0; GetValue(ref value); return value; } case DType.UInt64: { ulong value = 0; GetValue(ref value); return value; } case DType.Float: { float value = 0; GetValue(ref value); return value; } case DType.Double: { double value = 0; GetValue(ref value); return value; } case DType.String: { string value = null; GetValue(ref value); return value; } case DType.Custom: { sbyte[] value = null; GetValue(ref value); return value; } case DType.Complex: { var value = Convert2Struct(this, valueType); if (value is null) throw new IACommServiceException(ErrorCode.DataTypeMismatch); return value; } default: { return null; } } } } public uint Set(object value) { if (value is null) return ErrorCode.InvalidArgument; if (value is DataValue_t) { if (DataType != ((DataValue_t)value).DataType || Dimensions.ToString() != ((DataValue_t)value).Dimensions.ToString()) return ErrorCode.DataTypeMismatch; CopyFrom((DataValue_t)value); return ErrorCode.Good; } Type valueType = value.GetType(); if (IsArray) { if (!valueType.IsArray) return ErrorCode.DataTypeMismatch; valueType = valueType.GetElementType(); } if (valueType.IsEnum) { if (DataType != DType.Int16) return ErrorCode.DataTypeMismatch; } else if (valueType.IsValueType && !valueType.IsPrimitive) { if (DataType != DType.Complex) return ErrorCode.DataTypeMismatch; } else if (DataType == DType.Complex || m_dataTypeDic[DataType] != valueType) { return ErrorCode.DataTypeMismatch; } if (IsArray) { var tempValue = value as Array; int[] tempDimensions = Array.ConvertAll(Dimensions, z => (int)z); if (tempValue.Rank != tempDimensions.Length) return ErrorCode.DataTypeMismatch; for (int index = 0; index < tempValue.Rank; index++) { if (tempValue.GetLength(index) != tempDimensions[index]) return ErrorCode.DataTypeMismatch; } if (valueType.IsEnum) { short[] arrayValue = new short[tempValue.Length]; for (int index = 0; index < arrayValue.Length; index++) { int[] indexes = null; ConvertIndex(index, tempDimensions, ref indexes); arrayValue[index] = Convert.ToInt16(tempValue.GetValue(indexes)); } return SetArrayValue(arrayValue); } else if (DataType == DType.Complex) { for (uint index = 0; index < ArraySize; index++) { int[] indexes = null; ConvertIndex((int)index, tempDimensions, ref indexes); DataValue_t element = new DataValue_t(DType.Complex); var structElement = tempValue.GetValue(indexes); var status = Convert2DataValue(structElement, element); if (ErrorCode.Good == status) status = SetElement(index, element); element.Dispose(); if (status != ErrorCode.Good) return status; } return ErrorCode.Good; } else { switch (DataType) { case DType.Boolean: { bool[] arrayValue = null; Convert2SingleDimensionArray(value as Array, tempDimensions, ref arrayValue); return SetArrayValue(arrayValue); } case DType.SByte: { sbyte[] arrayValue = null; Convert2SingleDimensionArray(value as Array, tempDimensions, ref arrayValue); return SetArrayValue(arrayValue); } case DType.Byte: { byte[] arrayValue = null; Convert2SingleDimensionArray(value as Array, tempDimensions, ref arrayValue); return SetArrayValue(arrayValue); } case DType.Int16: { short[] arrayValue = null; Convert2SingleDimensionArray(value as Array, tempDimensions, ref arrayValue); return SetArrayValue(arrayValue); } case DType.UInt16: { ushort[] arrayValue = null; Convert2SingleDimensionArray(value as Array, tempDimensions, ref arrayValue); return SetArrayValue(arrayValue); } case DType.Int32: { int[] arrayValue = null; Convert2SingleDimensionArray(value as Array, tempDimensions, ref arrayValue); return SetArrayValue(arrayValue); } case DType.UInt32: { uint[] arrayValue = null; Convert2SingleDimensionArray(value as Array, tempDimensions, ref arrayValue); return SetArrayValue(arrayValue); } case DType.Int64: { long[] arrayValue = null; Convert2SingleDimensionArray(value as Array, tempDimensions, ref arrayValue); return SetArrayValue(arrayValue); } case DType.UInt64: { ulong[] arrayValue = null; Convert2SingleDimensionArray(value as Array, tempDimensions, ref arrayValue); return SetArrayValue(arrayValue); } case DType.Float: { float[] arrayValue = null; Convert2SingleDimensionArray(value as Array, tempDimensions, ref arrayValue); return SetArrayValue(arrayValue); } case DType.Double: { double[] arrayValue = null; Convert2SingleDimensionArray(value as Array, tempDimensions, ref arrayValue); return SetArrayValue(arrayValue); } case DType.String: { string[] arrayValue = null; Convert2SingleDimensionArray(value as Array, tempDimensions, ref arrayValue); return SetArrayValue(arrayValue); } default: { return ErrorCode.DataTypeMismatch; } } } } else { if (valueType.IsEnum) { return SetValue(Convert.ToInt16(value)); } else if (DataType == DType.Complex) { Reset(DType.Complex); return Convert2DataValue(value, this); } else { switch (DataType) { case DType.Boolean: return SetValue((bool)value); case DType.SByte: return SetValue((sbyte)value); case DType.Byte: return SetValue((byte)value); case DType.Int16: return SetValue((short)value); case DType.UInt16: return SetValue((ushort)value); case DType.Int32: return SetValue((int)value); case DType.UInt32: return SetValue((uint)value); case DType.Int64: return SetValue((long)value); case DType.UInt64: return SetValue((ulong)value); case DType.Float: return SetValue((float)value); case DType.Double: return SetValue((double)value); case DType.String: return SetValue((string)value); case DType.Custom: return SetValue((sbyte[])value); default: return ErrorCode.DataTypeMismatch; } } } } public uint DataType { get { return m_value.DataType(); } } public bool IsArray { get { return m_value.IsArray(); } } public uint ArraySize { get { return m_value.ArraySize(); } } public uint[] Dimensions { get { uint[] dimensions = null; m_value.GetDimensions(ref dimensions); return dimensions; } } public object Value { get { if (DataType == DType.Complex) throw new IACommServiceException(ErrorCode.NotSupported); return Get(); } set { Set(value); } } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposeManaged) { if (!m_disposed) { if (disposeManaged) { //do nothing } if (!m_isReference) DataValueFactory4CSharp.Destroy(m_value); m_value = null; m_disposed = true; } } //Internal use public IDataValue4CSharp Internal { get { return m_value; } } private uint Convert2SingleDimensionArray(Array sourceArray, int[] dimensions, ref T[] targetArray) { if (null == sourceArray) return ErrorCode.InvalidArgument; targetArray = new T[sourceArray.Length]; for (int index = 0; index < targetArray.Length; index++) { int[] indexes = null; ConvertIndex(index, dimensions, ref indexes); targetArray[index] = (T)sourceArray.GetValue(indexes); } return ErrorCode.Good; } private uint Convert2MultiDimensionsArray(T[] sourceArray, int[] dimensions, ref Array targetArray) { if (null == sourceArray) return ErrorCode.InvalidArgument; targetArray = Array.CreateInstance(typeof(T), dimensions); for (int index = 0; index < sourceArray.Length; index++) { int[] indexes = null; ConvertIndex(index, dimensions, ref indexes); targetArray.SetValue(sourceArray[index], indexes); } return ErrorCode.Good; } private uint ConvertIndex(int index, int[] dimensions, ref int[] indexes) { if (null == dimensions) return ErrorCode.InvalidArgument; indexes = new int[dimensions.Length]; for (int n = 0; n < indexes.Length; n++) { int curLength = (int)dimensions[n]; int lengths = 1; for (int m = n + 1; m < indexes.Length; m++) { lengths *= (int)dimensions[m]; } indexes[n] = (index / lengths) % curLength; } return ErrorCode.Good; } private object Convert2Struct(DataValue_t value, Type structType) { object retValue = null; if (structType.IsValueType && !structType.IsPrimitive && !structType.IsEnum) { retValue = Activator.CreateInstance(structType); DataValue_t fieldValue = new DataValue_t(); var fieldInfos = structType.GetFields(); foreach (var fieldInfo in fieldInfos) { var status = value.GetValue(fieldInfo.Name, ref fieldValue); if (status != ErrorCode.Good) { fieldValue.Dispose(); throw new IACommServiceException(ErrorCode.InvalidArgument); } object field = null; try { field = fieldValue.Get(fieldInfo.FieldType); } catch { field = null; } fieldInfo.SetValue(retValue, field); } fieldValue.Dispose(); } return retValue; } private uint Convert2DataValue(object structValue, DataValue_t value) { var structType = structValue.GetType(); if (structType.IsValueType && !structType.IsPrimitive && !structType.IsEnum) { var fieldInfos = structType.GetFields(); foreach (var fieldInfo in fieldInfos) { object field = fieldInfo.GetValue(structValue); DataValue_t fieldValue = new DataValue_t(field); var status = value.SetValue(fieldInfo.Name, fieldValue); fieldValue.Dispose(); if (status != ErrorCode.Good) return ErrorCode.InvalidArgument; } return ErrorCode.Good; } else { return ErrorCode.DataTypeMismatch; } } } }