Working friendly with null object references through extended functions

本文探讨了C#中空引用的问题及处理方式,介绍了如何通过不同的编程策略来避免空引用错误,包括忽略空引用、检查变量是否为空以及使用扩展方法来简化代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

CodeProject
Introduction

I hate the null object reference error. It will decrease not only the quality but also the customer satisfaction. Entering the C# 3.0 times, the extended functions give us a powerful way to change our coding styles, including the approaches to null object references.

Rationalities for null references

However, the null object reference is reasonable. It is impossible to be eliminated from the codes. Dozens of codes will bring up null object references. They fall into at least three categories.

1.Widely used third-party components

Third party components prosper in the software development circles. It’s well-known that they boost the productivity, even the quality and scalability. However, not all the third party components are shipped with sufficient document to direct the programmers to code correctly with their interfaces, which will result in null object reference errors.

2.Web Services

In common sense, the response object returned from the web service proxy could not be null. However, the array in the response object will be null even if the web service returns an empty array instead of null.

3.List<T>.Find
Common approaches for null object references

Let’s start with a function definition.

public class TimeScheme {
        public long SchemeID { get; set; }
        public long[] TimeID { get; set; }
public string SchemeName { get; set; }
}
public void SaveObj(TimeScheme scheme, int count)
    {
        //...
    }

The parameter list of SaveObj function contains two parameters. Parameter scheme is a reference type that may be null object reference. Parameter count is a value type that never causes null object reference error.

Approach 1: Just think they always have instances

Just ignore you are coding with reference types. Rather, handling them as the way as value types. Here is the pre-condition that they can’t be null. The code is as follows:

public void SaveObj(TimeScheme scheme, string name, int count)
    {
        switch (scheme.SchemeID)
        { 
            case 1:
                //do something
                break;
            case 2:
                //do something
                break;

        }
}

If the scheme is null, the null object reference error arises. However, it is not bad. The pre-condition is that the scheme can not be null normally, if the null reference error arises, it indicates that something wrong in the running context. The exception will stop the error into the following workflow so that more serious bugs can be avoided. Meanwhile, the user and the programmer are alerted as well.

From the practical perspective, the code above is not effective to help us find the problem accurately. If the null object reference error appears in SaveObj, we can only get the message as the following form.

Test method MyTest.UnitTest1.TestNullReference threw exception: System.NullReferenceException: Object reference not set to an instance of an object.
MyTest.UnitTest1.SaveObj(TimeScheme scheme, String name, Int32 count) in C:\MyTest\UnitTest1.cs: line 131

In other words, we are alerted that null object reference arises in SaveObj function. However, we can’t figure out which reference value cause the error.

To be frank, the code above is almost useless to help us find out the problem. If we write more code to guard the scheme value, the error message will be more helpful.

public void SaveObj(TimeScheme scheme, string name, int count)
        {
            if (scheme == null)
                throw new ArgumentNullException("scheme");

            switch (scheme.SchemeID)
            {
                case 1:
                    //do something
                    break;
                case 2:
                    //do something
                    break;

            }
        }

The error message will be the following.

Test method MyTest.UnitTest1.TestNullReference threw exception: System.ArgumentNullException: Value cannot be null.
Parameter name: scheme. MyTest.UnitTest1.SaveObj(TimeScheme scheme, String name, Int32 count) in C:\MyTest\UnitTest1.cs: line 131

However, if we implement this approach strictly, many codes as if(scheme==null) will be added. It will increase the code scale as well as the typing workloads. Here is the problem we will address.

Approach 2: Think they may be null references

Here is the pre-condition that they can be null. So we must keep it in mind, evaluating the variable before using them. The code will be written similar to the following form.

public void SaveObj(TimeScheme scheme, string name, int count)
        {
            if (scheme != null)
            {

                switch (scheme.SchemeID)
                {
                    case 1:
                        //do something
                        break;
                    case 2:
                        //do something
                        break;

                }
            }
        }

If we implement this approach strictly, many if-else codes will be introduced into the already-being-complex project. Can we make it simplier?

More practically, both of the pre-conditions may exist in the same context.

The Answer to the Null Object References

Since the null object references are reasonable, the answer would be how we can work friendly with the null object references substantially.

For pre-condition that the values can’t be null object references, the code will be written in this form.

public void SaveObj(TimeScheme scheme, string name, int count)
        {

            switch (scheme.UnSafeItem("scheme").SchemeID)
            {
                case 1:
                    //do something
                    break;
                case 2:
                    //do something
                    break;

            }
        }

If the variable scheme is null, we can get the more helpful message as the following.Test method MyTest.UnitTest1.TestNullReference threw exception:

System.ArgumentNullException: Value cannot be null.
Parameter name: scheme.
Nova.SafeItems.ExtendedEnumerable.UnSafeItem[T](T item, String itemName) in C:\MyTest\SafeItems.cs: line 203
MyTest.UnitTest1.SaveObj(TimeScheme scheme, String name, Int32 count) in C:\MyTest\UnitTest1.cs: line 138
MyTest.UnitTest1.TestNullReference() in C:\MyTest\UnitTest1.cs: line 153

Oh, line 138 is line where the error occurs. We almost don’t change the code except the UnSafeItem(“scheme”), which is a extended method.

For pre-condition that the variable may be null object references, the code will be written in this form.

public void SaveObj(TimeScheme scheme, string name, int count)
        {
            scheme.SafeItem((n) => {
                switch (n.SchemeID)
                { 
                    case 1:
                        //do something
                        break;
                    case 2:
                        //do something
                        break;

                }
            });
        }

The switch block will be implemented only if scheme is not null.

SafeItem<T>(this T, Action<T>) makes sure that Action<T> is invoked only if variable T refers to a valid reference. UnSafeItem<T>(this T, string) throws ArgumentNullException if the variable T refers to null reference. In addition, more Safe series of extended functions are shipped in SafeItems.cs. I believe they will change the way of writing code.

Here I’d like to end up the writing with a comparison between the traditional codes and the extended safe codes in the real world.

[The traditional codes]

private static bool CheckTimes(SearchTimeParameter parameter, DateTime startDate)
        {
            if (parameter.IsXBooking
                && parameter.Item.CentralTimes != null && parameter.Item.Times.Length > 0)
            {
                foreach (DateTime time in parameter.Item.Times)
                {
                    if (time.TimeOfDay == startDate.TimeOfDay)
                    {
                        return true;
                    }
                }
                return false;
            }
            else
            {
                return true;
            }
        }

[The extended safe codes]

private static bool CheckTimes(SearchTimeParameter parameter, DateTime startDate)
        {
            return !parameter.UnSafeItem("parameter").IsXBooking
                || parameter.Item.UnSafeItem("parameter.Item").Times.SafeCount == 0
                || parameter.Item.Times.SafeExists(time => time.TimeOfDay == startDate.TimeOfDay);
        }

Don’t you think the extended safe codes are simpler?

Tips in UnSafeItem

UnSafeItem is just an idea in using the extended functions in C# 3.0.

public static T UnSafeItem<T>(this T item, string itemName) where T : class
        {
            if (item == null)
                throw new ArgumentNullException(itemName);
            else
                return item;
        }

 

 

I will appreciate any of your ideas.

转载于:https://www.cnblogs.com/czy/archive/2010/03/31/1701738.html

内容概要:本文针对国内加密货币市场预测研究较少的现状,采用BP神经网络构建了CCi30指数预测模型。研究选取2018年3月1日至2019年3月26日共391天的数据作为样本,通过“试凑法”确定最优隐结点数目,建立三层BP神经网络模型对CCi30指数收盘价进行预测。论文详细介绍了数据预处理、模型构建、训练及评估过程,包括数据归一化、特征工程、模型架构设计(如输入层、隐藏层、输出层)、模型编译与训练、模型评估(如RMSE、MAE计算)以及结果可视化。研究表明,该模型在短期内能较准确地预测指数变化趋势。此外,文章还讨论了隐层节点数的优化方法及其对预测性能的影响,并提出了若干改进建议,如引入更多技术指标、优化模型架构、尝试其他时序模型等。 适合人群:对加密货币市场预测感兴趣的研究人员、投资者及具备一定编程基础的数据分析师。 使用场景及目标:①为加密货币市场投资者提供一种新的预测工具和方法;②帮助研究人员理解BP神经网络在时间序列预测中的应用;③为后续研究提供改进方向,如数据增强、模型优化、特征工程等。 其他说明:尽管该模型在短期内表现出良好的预测性能,但仍存在一定局限性,如样本量较小、未考虑外部因素影响等。因此,在实际应用中需谨慎对待模型预测结果,并结合其他分析工具共同决策。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值