C# - 调用具有所有默认的参数结构构造函数 [英] C# - Calling a struct constructor that has all defaulted parameters
问题描述
我创建一个结构
来容纳一组数据时,今天就遇到了这个问题。下面是一个例子:
公共结构ExampleStruct
{
公共int值{搞定;私人集; }
公共ExampleStruct(int值= 1)
:这()
{
值=价值;
}
}
看起来很好,很正常。问题是,当我尝试使用此构造而不指定值,并希望使用的1违约值的参数:
私有静态无效的主要(字串[] args)
{
ExampleStruct例1 =新ExampleStruct();
Console.WriteLine(example1.Value);
}
这代码输出 0
但不输出 1
。其原因是,所有的结构都公开参数较少的构造。所以,就像我如何打电话这()
我明确的构造,在主
,那会发生同样的事情,其中新ExampleStruct()
实际上是调用 ExampleStruct()
,但不是要求 ExampleStruct(int值= 1 )
。因为它确实是,它使用了 INT
的0默认值值
。
更糟糕的是,我的实际代码检查,看到 int值= 1
参数是在构造函数中的有效范围内。这种添加到 ExampleStruct(int值= 1)
构造上面:
如果(价值< 1 ||值> 3)
{
抛出新的ArgumentException(值超出范围);
}
所以,它现在站,默认的构造函数实际创建一个对象,在我需要它的上下文中无效。任何人都知道我怎么可以:
- 系统。调用
ExampleStruct(int值= 1)
构造。 - 乙。修改默认值是如何填充的
ExampleStruct()
构造。 - ℃。其他一些建议/选项。
另外,我知道我可以用一个字段这样的,而不是我的值
属性:
公共只读int值;
但我的理念是,除非他们是私自使用领域常量
或静态
。
最后,我使用的原因结构
,而不是类
是因为这仅仅是一个对象持有的非可变数据,它应该在建造时充分填充,当作为参数传递,不应该能够为空
(因为它是按值传递作为结构
),这就是结构体的设计为。
其实,MSDN对一些很好的指导结构
考虑定义一个类的结构,而不是如果
型的实例是小和通常短。住或通常嵌入在
其它目的
不要定义除非该类型具有以下所有
特性的结构:对>
这在逻辑上代表一个值,类似于原始类型
(整数,双,等)。
它有一个实例大小超过16个字节小。
这是不可改变的。
它不会有要经常装箱。
块引用>
注意,他们是的考虑的一个
结构方面的考虑
,它决不是这个的应的始终是一个结构。这是因为选择使用结构
可以拥有性能和使用情况的影响(正面和负面的),并应慎重选择。
$ B尤其$ b请注意,他们不推荐
结构
事情> 16个字节(然后复制的成本比复制一个参考更贵)。
现在,对于你的情况,确实没有好的办法做到这一点以外建立一个工厂来生成一个
结构
你在默认状态下,或做某种诱骗
你的财产将其骗入初始化在第一次使用。
记住,
结构
应该工作,这样新X()
==默认(X)
,就是一个新建的结构
将包含的所有字段的默认值结构
。这是非常明显的,因为C#会的不的让你定义一个无参数的构造函数结构
,但奇怪的是,他们让所有的参数是拖欠而不发出警告。
这样,其实我建议你坚持使用
类
并使其不可变的,只是检查空
上,它被传递给方法。公共类ExampleClass中
{
//拥有财产性公开默认如果没有设置
公共int值{搞定;私人集; }
//删除默认,不工作
公共ExampleStruct(int值)
{
值=价值;
}
}
然而后,如果您绝对的必须的有
结构
其他原因 - 但是请注意结构
的费用,作为复制的演员,等等 - 你可以这样做:公共结构ExampleStruct
{
私人诠释? _值;
//已财产公开默认如果没有设置
公共int值
{
得到{_value? 1; }
}
//删除默认,不工作
公共ExampleStruct(int值)
:这()
{
_value =值;
}
}
请注意,默认情况下,
可空< INT>
将空
(即的HasValue ==虚假
) ,因此,如果这是真的,我们没有设置它,并且可以使用空合并运算符来回报广大的1
,而不是默认的。如果我们的没有的设置它在构造函数中,将非空,并采取价值,而不是...I ran into this issue today when creating a
struct
to hold a bunch of data. Here is an example:public struct ExampleStruct { public int Value { get; private set; } public ExampleStruct(int value = 1) : this() { Value = value; } }
Looks fine and dandy. The problem is when I try to use this constructor without specifying a value and desiring to use the defaulted value of 1 for the parameter:
private static void Main(string[] args) { ExampleStruct example1 = new ExampleStruct(); Console.WriteLine(example1.Value); }
This code outputs
0
and does not output1
. The reason is that all structs have public parameter-less constructors. So, like how I'm callingthis()
my explicit constructor, inMain
, that same thing occurs wherenew ExampleStruct()
is actually callingExampleStruct()
but not callingExampleStruct(int value = 1)
. Since it does that, it usesint
's default value of 0 asValue
.To make matters worse, my actual code is checking to see that
int value = 1
parameter is within a valid range within the constructor. Add this to theExampleStruct(int value = 1)
constructor above:if(value < 1 || value > 3) { throw new ArgumentException("Value is out of range"); }
So, as it stands right now, the default constructor actually created an object that is invalid in the context I need it for. Anyone know how I can either:
- A. Call the
ExampleStruct(int value = 1)
constructor.- B. Modify how the default values are populated for the
ExampleStruct()
constructor.- C. Some other suggestion/option.
Also, I am aware that I could use a field like this instead of my
Value
property:public readonly int Value;
But my philosophy is to use fields privately unless they are
const
orstatic
.Lastly, the reason I'm using a
struct
instead of aclass
is because this is simply an object to hold non-mutable data, should be fully populated when it is constructed, and when passed as a parameter, should not be able to benull
(since it is passed by value as astruct
), which is what struct's are designed for.解决方案Actually, MSDN has some good guidance on
struct
Consider defining a structure instead of a class if instances of the type are small and commonly short-lived or are commonly embedded in other objects.
Do not define a structure unless the type has all of the following characteristics:
It logically represents a single value, similar to primitive types (integer, double, and so on).
It has an instance size smaller than 16 bytes.
It is immutable.
It will not have to be boxed frequently.
Notice that they are considerations for considering a
struct
, and its never a "this should always be a struct". That is because the choice to use astruct
can have performance and usage implications (both positive and negative) and should be chosen carefully.Notice in particular that they don't recommend
struct
for things > 16 bytes (then the cost of copying becomes more expensive than copying a reference).Now, for your case, there is really no good way to do this other than to create a factory to generate a
struct
for you in a default state or to do some sort oftrick
in your property to fool it into initializing on first use.Remember, a
struct
is supposed to work such thatnew X()
==default(X)
, that is, a newly constructedstruct
will contain the default values for all fields of thatstruct
. This is pretty evident, since C# will not let you define a parameterless constructor for astruct
, though it is curious that they allow all arguments to be defaulted without a warning.Thus, I'd actually suggest you stick with a
class
and make it immutable and just check fornull
on the methods that it gets passed to.public class ExampleClass { // have property expose the "default" if not yet set public int Value { get; private set; } // remove default, doesn't work public ExampleStruct(int value) { Value = value; } }
However, if you absolutely must have a
struct
for other reasons - but please consider the costs ofstruct
such as copy-casts, etc - you could do this:public struct ExampleStruct { private int? _value; // have property expose the "default" if not yet set public int Value { get { return _value ?? 1; } } // remove default, doesn't work public ExampleStruct(int value) : this() { _value = value; } }
Notice that by default, the
Nullable<int>
will benull
(that is,HasValue == false
), thus if this is true, we didn't set it yet, and can use the null-coalescing operator to return our default of1
instead. If we did set it in the constructor, it will be non-null and take that value instead...这篇关于C# - 调用具有所有默认的参数结构构造函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!