给定接口类型的方法参数,如果消费者可以提供引用类型或未知值类型,即开发人员不知道的结构类型,如何保护方法免受未初始化参数的影响在实施时?我不想检查传入的属性的特定属性值。我已经对这个主题进行了大量的搜索,并且找不到我正在寻找的信息。
E.g。
public interface IFoo {}
// A type I don't know about
public struct FooStruct : IFoo {}
public class FooClass : IFoo {}
......在其他一些课程中
public void DoSomething(IFoo foo)
{
// Check if foo is null or default of some value type
// Just like foo == null, this doesn't work for a value type
if (foo == default(IFoo)) throw new ArgumentNullException(nameof(foo));
}
答案 0 :(得分:3)
如果方法因为它们实际上不会中断,请不要担心初始值。与null
相比就足够了,因为您尝试使用指定的参数名称抛出先前的异常,而不是可怕的和非特定的NullReferenceException
; throw
的全部目的是添加更具体的细节,以便调用实现可以轻松修复他们做错的事情(或者至少报告更明智且更有意义的错误)。一个很好的例子就是Linq方法Enumerable.Take
由于count
而无法投掷; anything less than or equal to 0
simply results in an empty collection
话虽如此,如果FooStruct
的某些内容无效,应该为该无效性抛出一个特定的例外,不有点误导ArgumentNullException
。例如,考虑一下,虽然default(int)
是0
,但0
完全有效,无法传递到某些方法,如果不是,我们期望ArgumentOutOfRange
(希望提到有效范围)而不是ArgumentNull
我们知道的值是(并且永远不会)null
答案 1 :(得分:1)
当传递给接受此结构实现的接口的方法时,FooStruct将被装箱,因此您可以将其与null进行比较。也许你可能想读一下拳击,也许这篇文章也会有所帮助:Gotcha-When-Csharp-Structures-Implement-Interfaces
答案 2 :(得分:1)
对于不是structs
的{{1}},您可以将结构与Nullable<T>
(下面的Activation.CreateInstance)进行比较。
new MyStruct()
以上代码输出以下内容:
void Main()
{
FooStruct fooStruct = new FooStruct() { FooProp = 1234 };
FooStruct fooStructDefault = default(FooStruct);
FooClass fooClass = new FooClass();
FooClass fooClassDefault = default(FooClass);
IsDefaultIFoo(fooStructDefault).Dump();
IsDefaultIFoo(fooStruct).Dump();
IsDefaultIFoo(fooClassDefault).Dump();
IsDefaultIFoo(fooClass).Dump();
}
public bool IsDefaultIFoo(IFoo foo)
{
if(foo != null && foo.GetType().IsValueType)
{
return foo.Equals(Activator.CreateInstance(foo.GetType()));
}
else
{
return foo == default(IFoo);
}
}
public interface IFoo { }
public struct FooStruct : IFoo
{
public int FooProp { get; set;}
}
public class FooClass : IFoo { }
答案 3 :(得分:0)
根据contracts来推断您的代码通常很有帮助。
每个方法都有一些前提条件 - 被调用者应该满足的东西,以及后置条件 - 方法保证对有效输入做的事情。
例如,方法divide y by x
x
显然应该是非零蚂蚁,这是一个合理的前提条件。对于这种情况,后置条件是结果小于或等于提供的y
。
只能在有效输入上保证有效行为,因此没有理由抛出默认的struct值,因为它是默认的 - 而是做一些特定而合理的断言。
ArgumentNullException
之所以如此广泛,只是因为通常以某种方式使用参数,所以验证它们不是null是有意义的,否则你的方法会失败。