using System; using System.Data; using System.Diagnostics; using System.Threading; using System.Threading.Tasks; using Npgsql.Internal; using NpgsqlTypes; namespace Npgsql; /// /// A generic version of which provides more type safety and /// avoids boxing of value types. Use instead of . /// /// The type of the value that will be stored in the parameter. public sealed class NpgsqlParameter : NpgsqlParameter { /// /// Gets or sets the strongly-typed value of the parameter. /// public T? TypedValue { get; set { if (typeof(T) == typeof(object) && ShouldResetObjectTypeInfo(value)) ResetTypeInfo(); else DisposeBindingState(); field = value; } } /// /// Gets or sets the value of the parameter. This delegates to . /// public override object? Value { get => TypedValue; set => TypedValue = (T)value!; } private protected override Type StaticValueType => typeof(T); #region Constructors /// /// Initializes a new instance of . /// public NpgsqlParameter() { } /// /// Initializes a new instance of with a parameter name and value. /// public NpgsqlParameter(string parameterName, T value) { ParameterName = parameterName; TypedValue = value; } /// /// Initializes a new instance of with a parameter name and type. /// public NpgsqlParameter(string parameterName, NpgsqlDbType npgsqlDbType) { ParameterName = parameterName; NpgsqlDbType = npgsqlDbType; } /// /// Initializes a new instance of with a parameter name and type. /// public NpgsqlParameter(string parameterName, DbType dbType) { ParameterName = parameterName; DbType = dbType; } #endregion Constructors private protected override PgConcreteTypeInfo MakeConcreteForTypedValue(PgTypeInfo typeInfo, out object? providerWriteState) => typeInfo.MakeConcreteForValue( new() { NestedObjectDbNullHandling = ParameterDbNullHandling }, TypedValue, out providerWriteState); private protected override PgValueBinding BindTypedValue(PgConcreteTypeInfo concrete, object? providerWriteState, DataFormat? formatPreference) => concrete.BindParameterValue(TypedValue, providerWriteState, ParameterDbNullHandling, formatPreference); private protected override ValueTask WriteTypedValue(bool async, PgConverter converter, PgWriter writer, CancellationToken cancellationToken) { Debug.Assert(TypedValue is not null); if (async) return converter.WriteAsync(writer, TypedValue, cancellationToken); converter.Write(writer, TypedValue); return new ValueTask(); } private protected override void SetOutputTypedValue(NpgsqlDataReader reader, int ordinal) => TypedValue = reader.GetFieldValue(ordinal); private protected override NpgsqlParameter CloneCore() => // use fields instead of properties // to avoid auto-initializing something like type_info new NpgsqlParameter { _precision = _precision, _scale = _scale, _size = _size, _dbType = _dbType, _npgsqlDbType = _npgsqlDbType, _dataTypeName = _dataTypeName, Direction = Direction, IsNullable = IsNullable, _name = _name, TrimmedName = TrimmedName, SourceColumn = SourceColumn, SourceVersion = SourceVersion, TypedValue = TypedValue, SourceColumnNullMapping = SourceColumnNullMapping, }; }