C# - 调用具有所有默认的参数结构构造函数 [英] C# - Calling a struct constructor that has all defaulted parameters

查看:204
本文介绍了C# - 调用具有所有默认的参数结构构造函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建一个结构来容纳一组数据时,今天就遇到了这个问题。下面是一个例子:

 公共结构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 output 1. The reason is that all structs have public parameter-less constructors. So, like how I'm calling this() my explicit constructor, in Main, that same thing occurs where new ExampleStruct() is actually calling ExampleStruct() but not calling ExampleStruct(int value = 1). Since it does that, it uses int's default value of 0 as Value.

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 the ExampleStruct(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 or static.

Lastly, the reason I'm using a struct instead of a class 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 be null (since it is passed by value as a struct), 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 a struct 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 of trick in your property to fool it into initializing on first use.

Remember, a struct is supposed to work such that new X() == default(X), that is, a newly constructed struct will contain the default values for all fields of that struct. This is pretty evident, since C# will not let you define a parameterless constructor for a struct, 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 for null 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 of struct 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 be null (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 of 1 instead. If we did set it in the constructor, it will be non-null and take that value instead...

这篇关于C# - 调用具有所有默认的参数结构构造函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆