1

Let's imagine the following situation:

public class A
{
    private readonly Func<bool> _myFunction;
    ...
    public A(Func<bool> myFunction)
    {
        _myFunction = myFunction ?? throw new ArgumentNullException();
    }
}
public class B
{
    private bool _myBool;
    public bool MyBool => _myBool;
}
public class C
{
    A a;
    B b;
    ...
    public void SomeFunction()
    {
        a = new A( () => (bool)b?.MyBool );
    }
}

I would like to have the exception correctly raised in A constructor since I want _myFunction to be set to null if b has not been instantiated.

Basically something like:

if (b == null) {a = new A(null);} else {a = new A(() => b.MyBool);}

I have tried using the null-conditional operator to do so, but I have being unlucky and I just create a reference to a function that returns null.

Lenakeiz
  • 13
  • 3
  • Please clarify your specific problem or provide additional details to highlight exactly what you need. As it's currently written, it's hard to tell exactly what you're asking. – Community Nov 24 '22 at 22:08
  • Just to be clear, are you doing this so that when `_myFunction` runs, `b?.MyBool` is not null? Nothing you do in `SomeFunction` can actually ensure that, since `b` can be set to null at a later point. – Sweeper Nov 24 '22 at 22:09
  • @Sweeper I have modified the text to make more clear. I mainly want the exception to be raised in A constructor because b is currently null. – Lenakeiz Nov 24 '22 at 22:13
  • `b` may be `null` when `a` is created, but it may not be `null` when `a` calls my `_function`... – Orace Nov 24 '22 at 22:22

1 Answers1

-1

The shorter version is probably a = b is null ? new A(null) : new A(() => b.MyBool);

But it's not correct anyway:
Unless b is readonly, it can be modified and set to null before a call to the lambda.

b = null;
a.CallMyFunction(); // will call the lambda and fail to evaluate b.MyBool

A workaround is to use a local (and captured) copy of b to declare the lambda:

var b2 = b;
a = b2 is null ? new A(null) : new A(() => b2.MyBool)

But this time it doesn't respect good practice (SOLID principles):
A expect a non null function, it's not his responsibility to raise an exception if the caller can't build one.

The code should looks like this:

a = BuildAFromB(b); // pass a copy of b
// ....

// static to avoid ambiguity between the field b and the argument b
// To avoid this, it's in guidelines to prefix fields name with _
// _a, _b, ...
static A BuildAFromB(B b)
{
    if (b is null)
        throw new ArgumentException();

    return new A(() => b.MyBool);
}
Orace
  • 7,822
  • 30
  • 45
  • thank you very much for this. Yes I agree that for solid principles I should not test for null inside A function, but probably the short version you proposed is what I was looking for. – Lenakeiz Nov 25 '22 at 12:25
  • You can undelete your answer [here](https://stackoverflow.com/a/74561677/939213) so I can award you the bounty. If not it'll just go to waste. And it's not letting me award the bounty to a deleted question. Then post me some comment to remind me. – ispiro Nov 27 '22 at 21:45