8年前问Here问题,但我认为应该有一种方法(新模式,新设计,新架构或其他任何东西。)来强制执行方法不会返回null。
如您所知,在方法中返回null会产生一些影响,对我来说很重要的是:
在Consuming-Side和可理解的语义中处理null,如:
方法:
public ClassName Do()
{
...
return null;
}
调用Do()
之类的(注意评论也是):
var objVal = Do();
//Accessing property of ClassName raised exception
var pnVal = objVal.PropName;//Exception id objVal is null
//But I should handle if it is not null then do anything I want
if(objVal!= null)
{
//Do something
}
通过上述方式在产品上出现许多问题后,我得出了这个结论,概括了所有方法遵循模式可读,清晰和防止模糊语义。
所以一个非常基本的方法是使用Struct
类型,因为结构不能为null,如果返回类型的方法是结构,那么它们不能返回null,我们知道这在编译时< / strong>不在运行时。
所以我实现了上面的方法,如:
1-为方法制作DTO out
和in
,在这种情况下仅为out
:
public struct Do_DTO_Out
{
public ClassName Prop1 { get; set; }
public bool IsEmpty
{
get
{
return Prop1 == null;
}
}
public static Do_DTO_Out Empty
{
get
{
return new Do_DTO_Out() { Prop1 = null };
}
}
}
2- Do
方法应该是:
public Do_DTO_Out Do()
{
try
{
return manipulatedObj;
}
catch (Exception exp)
{
}
return Do_DTO_Out.Empty;
}
3-消费方:
var objVal = Do();
if (!objVal.IsEmpty)
//Do something
struct
是最好的方法吗?是否值得更改所有方法并为每个方法创建DTO in
和out
(我认为是这样)。
有没有更好的方法来做到这一点,任何想法,帮助,答案都会得到真正的赞赏。
答案 0 :(得分:3)
'带有属性检查的结构'转换的'引用类型'对我来说似乎没用。它还需要对您的意图有深入了解,而参考类型无效检查对于以后阅读它的人来说非常明显。
我认为code contracts可能适合你。它为您提供编译时静态分析和运行时检查。只要确保你有合适的合同作为后期条件:
public ClassName Do()
{
...
object returnValue = null;
Contract.Ensures(returnValue != null);
return returnValue;
}
答案 1 :(得分:1)
假设值永远不会是null
,否则if
是不可避免的(但对于单个方法调用,您现在可以编写Do()?.DoSomething()
)。
如果您可以引入代码合同(请参阅Patrick's answer),那么我完全同意Patrick的意见,您应该同意它们。如果它不可行(因为您的代码库已经太大了,或者您正在针对他们不受支持的环境),那么我首先使用断言:
var obj = Do();
Debug.Assert(obj != null);
// Use obj...
然而,我们将此责任转移到呼叫点,这可能是乏味的。如果你想让这个接口显式化,那么你可以按照你的想法使用某个结构但在调用点抛出异常(错误在哪里):
public NotNullable<SomeClass> Do() { }
NotNullable<T>
定义为:
public struct NotNullable<T> where T : class
{
public NotNullable(T value)
{
Value = value ?? throw new ArgumentNullException(nameof(value));
}
public T Value { get; }
}
但是,我不想在呼叫点明确访问.Value
,然后我将其透明添加:
public static implicit operator T(NotNullable<T> rhs)
=> rhs.Value;
现在来电者可以:
MyClass obj = Do();
obj.DoSomthing();
在创建对象时抛出正确的异常(在运行时,不幸)。使用[Conditional("DEBUG")]
时,您可以排除对发布版本的检查,该版本具有类似于Debug.Assert()
的行为和最小(但仍然存在)的开销。
请注意,仅当您希望直接在其签名中记录接口方法有关此约束时,这才有意义。如果您对此不感兴趣,请尽量保持简单:
public SomeClass Do()
{
MyClass somevalue = ...
// ...
return NotNull(somevalue);
}
其中NotNull()
是静态方法定义某处并使用using static
导入,甚至是object
的扩展方法,称为return somevalue.NotNull()
。
我不是特别喜欢这种方法,因为我觉得Debug.Assert()
在这些情况下已经足够了,但这只是我的观点。当然,也许有一天我们会在C#中使用Nullable Reference Types,然后我们将获得编译时强制执行(object?
或反过来object!
)。
答案 2 :(得分:0)
返回null是一个坏习惯-更好地实现 NullObject Design Pattern