Open frolra opened 2 months ago
Thanks. I'll look into adding support for it.
I started to create a DT class from ULINT if can help you :) `using System;
namespace L5Sharp.Core;
///
/// <summary>
/// Creates a new default <see cref="DT"/> type.
/// </summary>
public DT()
{
}
/// <summary>
/// Creates a new <see cref="DT"/> with the provided value.
/// </summary>
/// <param name="value">The value to initialize the type with.</param>
public DT(DateTime value)
{
_value = value;
}
/// <summary>
/// Creates a new <see cref="DT"/> value with the provided radix format.
/// </summary>
/// <param name="radix">The <see cref="Core.Radix"/> number format of the value.</param>
public DT(Radix radix) : base(radix)
{
}
/// <summary>
/// Creates a new <see cref="DT"/> with the provided value.
/// </summary>
/// <param name="value">The value to initialize the type with.</param>
/// <param name="radix">The optional radix format of the value.</param>
public DT(DateTime value, Radix radix) : base(radix)
{
_value = value;
}
/// <inheritdoc />
public override string Name => nameof(DT);
/// <inheritdoc />
public int CompareTo(object? obj)
{
return obj switch
{
null => 1,
DT typed => _value.CompareTo(typed._value),
AtomicData atomic => _value.CompareTo((DateTime)Convert.ChangeType(atomic, typeof(DateTime))),
ValueType value => _value.CompareTo((DateTime)Convert.ChangeType(value, typeof(DateTime))),
_ => throw new ArgumentException($"Cannot compare logix type {obj.GetType().Name} with {GetType().Name}.")
};
}
/// <inheritdoc />
public override bool Equals(object? obj)
{
return obj switch
{
DT value => value._value == _value,
AtomicData atomic => _value.Equals((DateTime)Convert.ChangeType(atomic, typeof(DateTime))),
ValueType value => _value.Equals(Convert.ChangeType(value, typeof(DateTime))),
_ => false
};
}
/// <inheritdoc />
public override int GetHashCode() => _value.GetHashCode();
/// <summary>
/// Parses a string into a <see cref="DT"/> value.
/// </summary>
/// <param name="value">The string to parse.</param>
/// <returns>A <see cref="DT"/> representing the parsed value.</returns>
/// <exception cref="FormatException">The <see cref="Radix"/> format can not be inferred from <c>value</c>.</exception>
public new static DT Parse(string value)
{
if (DateTime.TryParse(value, out var result))
return new DT(result);
var radix = Radix.Infer(value);
var atomic = radix.ParseValue(value);
var converted = (DateTime)Convert.ChangeType(atomic, typeof(DateTime));
return new DT(converted, radix);
}
/// <summary>
/// Tries to parse a string into a <see cref="DT"/> value.
/// </summary>
/// <param name="value">The string to parse.</param>
/// <returns>The parsed <see cref="DT"/> value if successful; Otherwise, <c>null</c>.</returns>
public new static DT? TryParse(string? value)
{
if (value is null || value.IsEmpty())
return default;
if (DateTime.TryParse(value, out var primitive))
return new DT(primitive);
if (!Radix.TryInfer(value, out var radix))
return default;
var parsed = radix.ParseValue(value);
var converted = (DateTime)Convert.ChangeType(parsed, typeof(DateTime));
return new DT(converted, radix);
}
// Contains the implicit .NET conversions for the type.
#region Conversions
/// <summary>
/// Converts the provided <see cref="DateTime"/> to a <see cref="DT"/> value.
/// </summary>
/// <param name="value">The value to convert.</param>
/// <returns>A <see cref="DT"/> value.</returns>
public static implicit operator DT(DateTime value) => new(value);
/// <summary>
/// Converts the provided <see cref="DT"/> to a <see cref="DateTime"/> value.
/// </summary>
/// <param name="atomic">The value to convert.</param>
/// <returns>A <see cref="DateTime"/> type value.</returns>
public static implicit operator DateTime(DT atomic) => atomic._value;
/// <summary>
/// Implicitly converts a <see cref="string"/> to a <see cref="DT"/> value.
/// </summary>
/// <param name="value">The value to convert.</param>
/// <returns>A new <see cref="DT"/> value.</returns>
public static implicit operator DT(string value) => Parse(value);
/// <summary>
/// Implicitly converts the provided <see cref="DT"/> to a <see cref="string"/> value.
/// </summary>
/// <param name="value">The value to convert.</param>
/// <returns>A new <see cref="string"/> value.</returns>
public static implicit operator string(DT value) => value.ToString();
#endregion
// Contains the IConvertible implementation for the type. I am explicitly implementing this interface for each
// atomic type to avoid polluting the API, and to have the implementation as performant as possible.
// To perform conversion, use the recommended .NET Convert.ChangeType() method and specify the target type.
#region Convertible
/// <inheritdoc />
TypeCode IConvertible.GetTypeCode() => TypeCode.Object;
/// <inheritdoc />
bool IConvertible.ToBoolean(IFormatProvider? provider) => _value.Ticks != 0;
/// <inheritdoc />
byte IConvertible.ToByte(IFormatProvider? provider) => (byte)_value.Ticks;
/// <inheritdoc />
char IConvertible.ToChar(IFormatProvider? provider) => (char)_value.Ticks;
/// <inheritdoc />
DateTime IConvertible.ToDateTime(IFormatProvider? provider) =>
throw new InvalidCastException($"Conversion from {Name} to {nameof(DateTime)} is not supported.");
/// <inheritdoc />
decimal IConvertible.ToDecimal(IFormatProvider? provider) =>
throw new InvalidCastException($"Conversion from {Name} to {nameof(Decimal)} is not supported.");
/// <inheritdoc />
double IConvertible.ToDouble(IFormatProvider? provider) => (double)_value.Ticks ;
/// <inheritdoc />
short IConvertible.ToInt16(IFormatProvider? provider) => (short)_value.Ticks;
/// <inheritdoc />
int IConvertible.ToInt32(IFormatProvider? provider) => (int)_value.Ticks;
/// <inheritdoc />
long IConvertible.ToInt64(IFormatProvider? provider) => _value.Ticks;
/// <inheritdoc />
sbyte IConvertible.ToSByte(IFormatProvider? provider) => (sbyte)_value.Ticks;
/// <inheritdoc />
float IConvertible.ToSingle(IFormatProvider? provider) => _value.Ticks;
/// <inheritdoc />
string IConvertible.ToString(IFormatProvider? provider) => ToString();
/// <inheritdoc />
object IConvertible.ToType(Type conversionType, IFormatProvider? provider)
{
var convertible = (IConvertible)this;
return Type.GetTypeCode(conversionType) switch
{
TypeCode.Boolean => convertible.ToBoolean(provider),
TypeCode.Byte => convertible.ToByte(provider),
TypeCode.Char => convertible.ToChar(provider),
TypeCode.DateTime => convertible.ToDateTime(provider),
TypeCode.Decimal => convertible.ToDecimal(provider),
TypeCode.Double => convertible.ToDouble(provider),
TypeCode.Empty => throw new ArgumentNullException(nameof(conversionType)),
TypeCode.Int16 => convertible.ToInt16(provider),
TypeCode.Int32 => convertible.ToInt32(provider),
TypeCode.Int64 => convertible.ToInt64(provider),
TypeCode.Object => ToAtomic(conversionType),
TypeCode.SByte => convertible.ToSByte(provider),
TypeCode.Single => convertible.ToSingle(provider),
TypeCode.String => ToString(),
TypeCode.UInt16 => convertible.ToUInt16(provider),
TypeCode.UInt32 => convertible.ToUInt32(provider),
TypeCode.UInt64 => convertible.ToUInt64(provider),
TypeCode.DBNull => throw new InvalidCastException(
"Conversion for type code 'DbNull' not supported by AtomicType."),
_ => throw new InvalidCastException($"Conversion for {conversionType.Name} not supported by AtomicType.")
};
}
/// <inheritdoc />
ushort IConvertible.ToUInt16(IFormatProvider? provider) => (ushort)_value.Ticks;
/// <inheritdoc />
uint IConvertible.ToUInt32(IFormatProvider? provider) => (uint)_value.Ticks;
/// <inheritdoc />
ulong IConvertible.ToUInt64(IFormatProvider? provider) => (ulong)_value.Ticks;
/// <summary>
/// Converts the current atomic type to the specified atomic type.
/// </summary>
/// <param name="conversionType">The atomic type to convert to.</param>
/// <returns>A <see cref="object"/> representing the converted atomic type value.</returns>
/// <exception cref="InvalidCastException">The specified type is not a valid atomic type.</exception>
private object ToAtomic(Type conversionType)
{
if (conversionType == typeof(BOOL))
return new BOOL(_value.Ticks != 0);
if (conversionType == typeof(SINT))
return new SINT((sbyte)_value.Ticks);
if (conversionType == typeof(INT))
return new INT((short)_value.Ticks);
if (conversionType == typeof(DINT))
return new DINT((int)_value.Ticks);
if (conversionType == typeof(LINT))
return new LINT(_value.Ticks);
if (conversionType == typeof(REAL))
return new REAL(_value.Ticks);
if (conversionType == typeof(LREAL))
return new LREAL(_value.Ticks);
if (conversionType == typeof(USINT))
return new USINT((byte)_value.Ticks);
if (conversionType == typeof(UINT))
return new UINT((ushort)_value.Ticks);
if (conversionType == typeof(UDINT))
return new UDINT((uint)_value.Ticks);
if (conversionType == typeof(ULINT))
return new ULINT((ulong)_value.Ticks);
throw new InvalidCastException($"Cannot convert from {GetType().Name} to {conversionType.Name}.");
}
#endregion
}`
Do you want to submit a PR?
Yep, i will review more deeply the code and i submit the PR 👍🏼
When I try to import my L5X file, the DataType read process throws me this exception:
The name 'DT' does not represent a known L5Sharp.Core.AtomicData type.
_at L5Sharp.Core.AtomicData.Parse(String name, String value) at L5Sharp.Core.LogixSerializer.DeserializeAtomic(XElement element) at L5Sharp.Core.LogixSerializer.DeserializeData(XElement element) at L5Sharp.Core.LogixSerializer.Deserialize(XElement element) at L5Sharp.Core.LogixSerializer.Deserialize[TElement](XElement element) at L5Sharp.Core.LogixElement.GetData() at L5Sharp.Core.Member.GetData() at L5Sharp.Core.Member.get_Value() at L5Sharp.Core.Tag.get_Value() at L5Sharp.Core.Tag.getDataType()I Checked at source code and missing this type definition. From Logix DT is Date/Time format and basically is a Unsigned integer 64 bits