0

I want to add nullable int? and keep null when all values are null.

I would like this results :

1 + 2 = 3
1 + null = 1
null + null = null
O + null = 0

The problem is that if I sum a value with null, the result is null

int? i1 = 1;
int? i2 = null;
int? total = i1 + i2; // null

I have seen this thread : Is there a more elegant way to add nullable ints?

With linq :

var nums = new int?[] {null, null, null};
var total = nums.Sum(); // 0

I get 0 and I want null...

The only way I have found is to make a function :

static int? Sum(params int?[] values)
{
  if (values.All(item => !item.HasValue))
    return null;
  else
    return values.Sum();
}

I there a way to do that natively ?

Mong Zhu
  • 23,309
  • 10
  • 44
  • 76
A.Baudouin
  • 2,855
  • 3
  • 24
  • 28
  • 4
    Well, writing a method is not a bad approach :) – Tim Schmelter Mar 08 '18 at 11:55
  • 2
    Create own type and operators and linq functions for it. – BWA Mar 08 '18 at 11:56
  • 2
    I don't understand which answer in the linked duplicate solves this issue. It's the thread that OP linked to so they've clearly read it. Can someone put me out of my misery? – Equalsk Mar 08 '18 at 12:01
  • 1
    The solution simply is using `GetValueOrDefault`. `int? total = i1.GetValueOrDefault() + i2.GetValueOrDefault(); // 1` – Salah Akbari Mar 08 '18 at 12:01
  • The number with the properties you describe is 0. Null isn't zero. You can't add something to null and expect to get anything other than null. You can use `??0` to replace it with 0 if you want – Panagiotis Kanavos Mar 08 '18 at 12:02
  • 4
    OP clearly says they want `null + null` to be `null`, not treated as `0`, this is why I'm confused. Who cares what the OPs reasoning is, it's what they've asked for. – Equalsk Mar 08 '18 at 12:03
  • @Equalsk the OP is asking for opposite behaviours at the same time. Worse, the *opposite* of the standard behaviour in each scenario. `1+null` alredy returns null but the OP wants 1. `nums.Sum()` ignores nulls but now the OP wants *nulls*. – Panagiotis Kanavos Mar 08 '18 at 12:03
  • @Equalsk you can't ask for a black white egg. You can ask for a black egg and a white egg. You can use different code snippets for different situations – Panagiotis Kanavos Mar 08 '18 at 12:04
  • 2
    I agree that what OP wants smells bad, but I don't see the contradiction in behaviour. They've said if all values are `null` they want the sum to be `null`, in any other case treat `null` as `0`. Seems straightforward to me. I don't understand how the duplicate answers the scenario OP is stuck on which is `null + null = null` and not `0`. Am I being unusually dense? – Equalsk Mar 08 '18 at 12:06
  • @Equalsk that's because you read only the latter half. The first says "I want 1 from 1+null" – Panagiotis Kanavos Mar 08 '18 at 12:07
  • @ PanagiotisKanavos: tho topic should not be closed, the proposed solution does not fit with the request. Actually I found a solution for the requestor by using manual sum with LINQ – Oxald Mar 08 '18 at 12:08
  • @A.Baudouin if you check [the source code](https://referencesource.microsoft.com/#System.Core/System/Linq/Enumerable.cs,1408) you'll see that `Sum(this IEnumerable source)` explicitly ignores nulls. You'll have to write your own method that returns null immediatelly if a null is detected – Panagiotis Kanavos Mar 08 '18 at 12:08
  • 1
    @PanagiotisKanavos ...which would be the scenario I mentioned where `null` would be treated as `0`... – Equalsk Mar 08 '18 at 12:08
  • I'd say the anwer is no, not natively. However, if you really want to do this, you could take a look at an "IL Weaver" like Fody. But I would advise against it. Not because weaving is a bad thing, but because you want something smelly :) – Frederick Grumieaux Mar 08 '18 at 12:10
  • 1
    The duplicate is not really one because OP knows that. He asks for a shorter way to do what his method does(return `Sum` only if not all are `null`). But there is none. So this question can be closed because it could only be answered with the method he has shown already in this question(maybe it could be rewritten to avoid double enumeration). – Tim Schmelter Mar 08 '18 at 12:11
  • 2
    Basically this boils down to [OP having an XY problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem) for something that smells bad and that writing the little function is the neatest way to solve it. I think I need to lie down... – Equalsk Mar 08 '18 at 12:13
  • What you are trying to do would work out-of-the-box if you simply used `0` instead of `null`. Why does it have to be `null`? – Manfred Radlwimmer Mar 08 '18 at 12:24
  • `something that smells bad` I am not convinced the OP's request smells bad. They are effectively asking for a sum function that acts like SQL Server's `SUM` acts (where `null` is returned only if there is no non-`null` data) - that seems reasonable to me. – mjwills Mar 08 '18 at 12:45
  • 1
    @Manfred Radlwimmer Sorry for the late response... I will not go into details but in my program, I am summing array of int? where there is a difference between 0 and null and I want to keep null on the result. – A.Baudouin Mar 08 '18 at 13:13
  • @mjwills Didn't realise SQL SUM behaved that way, TIL. Thanks. – Equalsk Mar 08 '18 at 13:20

2 Answers2

4

One option might be an extension method using Aggregate. Something like:

public static int? NullableSum(this IEnumerable<int?> values)
{
    return values.Aggregate((int?)null, (sum, value)   
        => value.HasValue ? (sum ?? 0) + value : sum + 0);
}

Functionality wise it does much the same thing as your custom Sum method, without iterating through the array twice.

Essentially it sets the initial value to null, but as soon as it sees any non null value it starts treating the null values as 0.

Thus, if all inputs are null it returns null - otherwise it acts basically the same way as LINQ's Sum.

mjwills
  • 23,389
  • 6
  • 40
  • 63
0

Another option is to add this. This is how can you return null from function.

public static int? Add(params int[] I)
{
    int? total = null;
    for (int i = 0; i < I.Length; i++)
    {
        int? item = I[i];
        if (item != null)
        {
            if (total == null)
            {
                total = item;
            }
            else
            {
                total += item;
            }
        }
    }
    return total;
 }

And now to use this function.

Add(5) // 5
Add() // null
Add(5,4) // 9
Add(5,4,10) // 19
     
Abdul Ahad
  • 99
  • 2
  • 9
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Mar 29 '23 at 00:38