C# 实施方法don';t返回空值
正如8年前提出的问题,但我认为应该有一种方法(新模式、新设计、新架构或其他任何东西)来强制方法不要返回null 正如您所知,在方法中返回null有一些含义,对我来说重要的一点是: 在消费端处理null和可理解的语义,如: 方法:C# 实施方法don';t返回空值,c#,oop,null,nullreferenceexception,C#,Oop,Null,Nullreferenceexception,正如8年前提出的问题,但我认为应该有一种方法(新模式、新设计、新架构或其他任何东西)来强制方法不要返回null 正如您所知,在方法中返回null有一些含义,对我来说重要的一点是: 在消费端处理null和可理解的语义,如: 方法: public ClassName Do() { ... return null; } 并调用Do()类似(注意注释): 在通过上述方式对产品提出了许多问题之后,我得出了这个结论,概括了所有方法,以遵循一种模式,使其可读、清晰,并防止语义歧义 所以一个非
public ClassName Do()
{
...
return null;
}
并调用Do()
类似(注意注释):
在通过上述方式对产品提出了许多问题之后,我得出了这个结论,概括了所有方法,以遵循一种模式,使其可读、清晰,并防止语义歧义
所以一个非常基本的方法是使用Struct
type,因为structure不能为null,如果方法的返回类型是structure,那么它们就不能返回null,我们在编译时知道这一点,而不是在运行时
因此,我实现了上述方法,如:
1-将方法的DTOout
和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
结构是不是最好的方法?是否值得更改所有方法并为每个方法创建DTOin
和out
(我认为是这样)
如果有更好的方法,任何想法、帮助和答案都将不胜感激。您的“引用类型”到“带属性检查的结构”转换对我来说似乎毫无用处。它还需要对您的意图有深入的了解,而引用类型null检查对于以后阅读它的任何人来说都是非常明显的 我想这对你有用。它为您提供编译时静态分析和运行时检查。只要确保你有合适的合同作为岗位条件:
public ClassName Do()
{
...
object returnValue = null;
Contract.Ensures(returnValue != null);
return returnValue;
}
假设该值永远不能为
null
,否则if
是不可避免的(但对于单个方法调用,您现在可以编写Do()?.DoSomething()
)
如果您可以引入代码契约(请参阅),那么我完全同意Patrick的观点,您应该遵循它们。如果它不可行(因为您的代码库已经太大,或者您的目标环境不支持它们),那么我首先使用断言:
var obj = Do();
Debug.Assert(obj != null);
// Use obj...
然而,我们正在将这一责任转移到呼叫点,这可能是乏味的。如果您想使这个接口显式化,那么您可以像您所想的那样使用struct,但在调用点抛出异常(错误是):
现在,来电者可以是:
MyClass obj = Do();
obj.DoSomthing();
当创建对象时,会抛出适当的异常(不幸的是在运行时)。使用[Conditional(“DEBUG”)]
时,您可以排除对具有类似于DEBUG.Assert()
的行为且开销最小(但仍然存在)的发布版本的检查
请注意,只有当您希望在其签名中直接记录有关此约束的接口方法时,这才有意义。如果您对此不感兴趣,请尽量简单:
public SomeClass Do()
{
MyClass somevalue = ...
// ...
return NotNull(somevalue);
}
其中,NotNull()
是一个在某处定义的静态方法,它与使用static的一起导入,甚至是一个名为return somevalue.NotNull()的对象的扩展方法
我并不特别喜欢这种方法,因为我认为在这种情况下,Debug.Assert()
就足够了,但这只是我的观点。当然,也许有一天我们会使用C语言,然后我们会得到编译时强制(作为对象?
,或者反过来作为对象!
)。返回null是一种不好的做法-最好实现
@Aria方法不会返回null
,因为它返回的是一个结构,但它仍然返回一个带有空引用的结构,如果您检查IsEmpty
,那么您拥有相同的代码(在调用点),如果您没有,那么您拥有完全相同的异常(在调用点)。您只需支付一些开销(并为原始代码添加一些模糊性)。如果这是一定不能发生的事情,那么我同意Patrick的观点:代码契约(或者,如果您以核心为目标,至少是断言)。“正如您所知,在方法中返回null会有一些问题”-哪一个会是?当然有“暗示”——但问题是什么?所以你用更糟糕的方法来规避它@Aria@Aria请注意,如果永远不允许使用null
(并且您不能引入契约),那么您应该在假设的NotNull
结构中进行一些检查(至少在创建值时,而不是在使用值时,您会得到一个异常(以后可能会以不明显的方式进行优化).@Fildor编辑的问题变成了暗示,谢谢。我的英语仍然很差。为什么不调用验证方法而不是创建结构?@AdrianoRepetti感谢您的努力和关注,但对我来说最大的好处是编译时,不要让方法返回空值。@Aria我想是的,这是您唯一可以满足的编译时要求n add是契约(但它们不会跨越WCF服务边界)。现在它们是你能做的最好的(AFAIK),然后是契约。确保是我想要的(编译时),如果消费者和服务处于不同的层,我的意思是我不希望服务的操作返回,你不能在那里使用相同的方法吗?如果我理解你,不,因为将来消费者可能是外部产品,而不是我们的。@Aria是服务还是消费者可能是第三方?那么我不明白问题所在。如果你确定在服务中,返回的项永远不会为null,然后在接口描述中说明。如果在必须返回null的情况下是错误/失败,则异常/错误结果是正确的方法。当然,这也必须在文档中说明。
public struct NotNullable<T> where T : class
{
public NotNullable(T value)
{
Value = value ?? throw new ArgumentNullException(nameof(value));
}
public T Value { get; }
}
public static implicit operator T(NotNullable<T> rhs)
=> rhs.Value;
MyClass obj = Do();
obj.DoSomthing();
public SomeClass Do()
{
MyClass somevalue = ...
// ...
return NotNull(somevalue);
}