简体   繁体   中英

Nullable<Nullable> or Optional<Nullable> in C#

Since the first comment on this question will probably be why and the why is what likely makes this not a duplicate question: I have a value type variable (of type decimal if that matters) that has three valid states: has value | null | unspecified has value | null | unspecified has value | null | unspecified . It would be best to represent all three of these states without a custom class. Also, 0.0m and any other decimal value are valid. Unfortunately, Nullable<Nullable<decimal>> is not valid in C#. What is the best way to do this?

UPDATE:

Eric's comments below caused me to think about this a bit differently. Coming at the question above as a software architect, the core philosophical question is how to handle the case where null can represent multiple meanings. The particular example that motivated this question is:

In our system, there are tables with product offerings (price, minimum order quantity, some user defined values, etc). The tables have hierarchy. In order to compute the offer values in the child table the "parent offers" need to be considered. The idea is for null to represent the case where a constraint has been removed and null(null) (for lack of a better syntax) to imply no change to the parent value.

Now, granted, C# is used (abused?) in a strictly functional manner by us, consequence being that needs are sometimes orthogonal to C#'s purpose. Hopefully the next version of C# has discriminated unions which would be perfect for this.

If you absolutely, positively, do not want to use a custom class or enum, I would say your best option is to use KeyValuePair<decimal, T> where T is some representation of your 3 options ( string for "unspecified"/"has value"/"null", int for -1/0/1, as you like)

I feel like this is pretty bad practice, but as per your specifications of no custom class, that's the best I've got.

Another non-ideal, but possibly workable, solution might be to use a Tuple<decimal?, bool>:

Tuple.Create<decimal?, bool>(null, true); //specified null
Tuple.Create<decimal?, bool>(null, false); //unspecified null
Tuple.Create<decimal?, bool>(1.0m, true);  //specified value
Tuple.Create<decimal?, bool>(1.0m, false); //??? insanity

I recommend to write your own implementation of such concept.

Minimal version may look like this:

sealed class Assignable<T>
{
    private readonly isAssigned;
    private readonly T value;

    public Assignable()
    {
    }

    public Assignable(T value)
    {
        this.value = value;
        this.isAssigned = true;
    }

    public T Value
    {
        get
        {
            if (!isAssigned) throw new InvalidOperationException();
            return value;
        }
    }

    public bool IsAssigned
    {
        get { return isAssigned; }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM