In C # with types everything is fine

After reading the article “ Strengthening Type Control: where in a typical C # -project there is an unsolicited element of weak typing? "Was quite surprised by the fallacy of this approach, and by the fact that no one paid attention to it.

The author of the post gives the idea that a method that returns a reference type whose object is created from a certain repository should, in one way or another, ensure that the returned object is not null. Moreover, in one example, he uses contracts, which contradicts their principles. I want to make out the fallacy of this approach.

We have a method GetItemthat pulls an object from a certain repository and should, according to the author’s intention, ensure that the object is not null.

public Item GetItem(int itemId)
{
    return dataAccessor.getItemById(itemId);
}


If the desired object was not in the repository, it dataAccessorwill return null, which will be given to the client and that, without checking the value for null, will receive a NullReferenceException. So how can one guarantee that this will not happen?

You can squeeze a null check inside the method and throw an Exception if the object is not found. But with this, we simply rename NullReferenceException to, for example, ItemNotFoundException. Moreover, now the client is required to add a try-catch block each time this method is accessed. Client writer will be very happy.

Another option is to add a post-condition to the method. Like this:

public Item GetItem(int itemId)
{
    Contract.Ensures(Contract.Result() != null);
    return dataAccessor.GetItemById(itemId);
}


Here everything becomes very bad and there are fewer kittens in the world. After reading the contract, anyone should understand that this method will always return an object, with any identifier provided. But this is unreal. The method cannot guarantee that an object with this Id is in the repository. So you need to add a pre-condition that will help the poor fellow and push all the problems to the client:

public Item GetItem(int itemId)
{
    Contract.Requires(dataAccessor.GetItemById(itemId) != null)
    Contract.Ensures(Contract.Result() != null);
    return dataAccessor.GetItemById(itemId);
}


Fun, isn't it? To get an object from the repository, you first need to pull the object out of the repository, for which you need to pull the object out of the repository, for which ... The

truth is that there is no spoon, no one can guarantee the existence of the object in the repository. The only way to guarantee the existence of any object is to create it and pinch its link. Everything else is bad design. The data access layer should get the object from the repository and pass it to the client. He does not know how to handle the absence of an object and does not even know if it is bad. The logic level is responsible for this.

The inability to guarantee the existence of an object outside the field of visibility leads to the second idea given in the article at the link above. Using a nullable container for reference types. I rephrase: nullable reference. Oil is oil. It was strange to learn about the popularity of this pattern.

The reference type may refer to null. Why stick one reference type into another and add the HasValue property to the container is definitely not clear to me. To check on HasValue? What prevents you from accessing the content object without this check? You can just as well carelessly not check for null through inequality. Moreover, this pattern is not only useless, but also harmful. Take a look at the following code:

public Maybe SomeMethod()
{
    var mbItem = GetMbItem();
    if(mbItem.HasValue)
    {
        var item = mbItem.Value;
        ModifyItem(ref item); 
    }
    return mbItem;
}


If the ModifyItem method has replaced the object, the SomeMethod method will return a container with the old object. Go later, look for this bug.

In general, I find the practice shown in that article harmful. There are standard tools for checking null references in C #, and you need to be careful not to allow a NullReferenceException. To complicate the system for this is not necessary. When working with repositories, you need to monitor data integrity and you won’t run away from this. If there is no object in the repository that must be there, it is much, much worse.

Also popular now: