Extending that thought a bit, from what I could determine Equals is a bit 
nuanced as well. First argument x appears to be cached or disassembled, 
whereas it would seem second argument y appears to be assembled version of 
the same.

protected virtual bool Equals(P x, P y) => x is IEquatable<P> xe && y is 
IEquatable<P> ye && xe.Equals(ye);

public new virtual bool Equals(object x, object y)
{
    object Normalize(object value) => value switch
    {
        null => null,
        R r => Disassemble(r),
        P p => p,
        _ => throw new InvalidOperationException($"Unsupported equality 
value type '{value.GetType()}'.")
    };

    x = Normalize(x);
    y = Normalize(y);

    return (x is null && y is null)
        || ReferenceEquals(x, y)
        || (x is P xp && y is P yp && Equals(xp, yp))
        //|| (x is R xr && y is R yr && Equals(xr, yr))
        ;
}

It's unlikely probably would see an R clause (returned class), as 
contrasted with the P clause (primitive class).

The Normalize local function is also geared at any rate along the same 
lines to compare vis-a-vis the primitive type.

Then Equals(P, P), after having ruled out null and reference equality, base 
implementation whether P is IEquatable<P> can just do it then.

Allowing for authors to extend as needed.

On Tuesday, June 10, 2025 at 1:13:17 PM UTC-4 Michael W Powell wrote:

> Hello,
>
> Double checking my work implementing IUserType. Implementing to facilitate 
> mapping types to postgres Npgsql. Specifically in one case to JSON/JSONB 
> column types, facilitated by either string, then to Newtonsoft.Json.Linq 
> JObject or JArray, both JContainer, depending on the use case.
>
> Best I can figure, Assemble and Disassemble are somewhat core and central 
> of such an implementation. Around the NullSafeGet and Set, for instance. 
> Almost to a point where it might be worth providing a generic serialization 
> implementation, interface, etc, but starting from here:
>
> public virtual object NullSafeGet(DbDataReader rs, string[] names, 
> ISessionImplementor session, object owner)
> {
>     this.VerifyNullSafeNames(names: names);
>
>     var name = names[0];
>     var ordinal = rs.GetOrdinal(name);
>     var value = rs[ordinal];
>     return value switch
>     {
>         null => null,
>         P p => Assemble(p, owner),
>         _ => throw new InvalidOperationException($"Unable to get null safe 
> value, names: [{string.Join(", ", names)}].")
>     };
> }
>
> public void NullSafeSet(DbCommand cmd, object value, int index, 
> ISessionImplementor session)
> {
>     // We expect there to be an parameter of this type.
>     if (cmd.Parameters.TryGetValue<NpgsqlParameter>(index, out var arg))
>     {
>         // Parameter Value may be either null, of types R or P, otherwise 
> throw.
>         arg.Value = value switch
>         {
>             null => null,
>             R r => Disassemble(r),
>             P p => p,
>             _ => throw new InvalidOperationException($"Unable to set null 
> safe value type '{value.GetType()}' index {index}.")
>         };
>
>         // Indeed return here since we do not want to throw the default 
> parameter ex.
>         return;
>     }
>
>     throw new InvalidOperationException($"Unable to set null safe 
> parameter value index {index}.");
> }
>
> Here I verify names apart from the implementation. Also I look up the 
> postgres Npgsql parameter in this instance.
>
> But the core of the approach, I think, are Assemble and Disassemble, from 
> what I can gather. Everything revolves around that, including DeepCopy.
>
> Mostly everything else is pretty boilerplate, in my estimation, so any 
> specialization can focus on the A/D overrides. Sometimes perhaps also the 
> Equals.
>
> public abstract class NpgsqlJsonCustomTypeBase<P, R> : IUserType
> {
>     // ...
> }
>
> Have verified through mappings and to a test project, seems to satisfy 
> things.
>
> Posting here in case I am missing something, perhaps there are gaps I am 
> unaware of.
>
> Appreciate the feedback.
>
> Best regards,
>
> Michael W. Powell
>

-- 
You received this message because you are subscribed to the Google Groups 
"Fluent NHibernate" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion visit 
https://groups.google.com/d/msgid/fluent-nhibernate/7f404b09-59ee-4565-9164-8cad298b308fn%40googlegroups.com.

Reply via email to