简体   繁体   中英

Object Initializer force compile error

Is it possible to enforce rules or throw an error when using object initializers in C#? I'd like to throw a compiler error or warning if an object is initialized but is missing a certain property.

public class Party
{
    public string Name { get; set; }
    public string Date { get; set; }
    public Location Location { get; set; }
}

public class SignUpForParty
{
    public void DoSomething()
    {
        Party party = new Party()
        {
            Name = "New Years Party!",
            Date = "Dec 31, 1999"
            // Show WARNING/ERROR here because no Location given
        };
    }
}

Essentially, I'm looking for a way to ensure that all objects of type Party are created with valid data for every instance.

Obviously I could do this with overloaded constructors, but in some cases I have a lot of properties and writing constructors to match is messy. I'd like to follow a cleaner C# style.

Obj p = new Obj(1, 2, 3,...n); // too many properties to be pretty

Obviously I could do this with overloaded constructors, but in some cases I have a lot of properties and writing constructors to match is messy. I'd like to follow a cleaner C# style.

Object initializers really shouldn't be considered alternatives to writing a constructor.

You should always include constructors in your types if you have requirements like this. It is a good idea to create a default set of constructors (or use optional arguments on one constructor) which at least provide a guarantee that the object will always be created in a valid, meaningful state.

Object initializers are helpful for optional properties, but shouldn't be relied upon for requirements of your type itself.

You cannot force every property to be initialized with an object initializer.

Even if you could, a consumer of the object could provide default (0, null, ...) values. Depending on your needs, consider validating object state at key times (eg before it can be saved to a database).

If you go that route, have a look at the IDataErrorInfo interface.

If your type is not valid when only 2 properties are set then you need to fix your design, not emit an error.

You provide a default constructor, which tells me that I don't have to set anything to use the object after initialization. You provide getters and setters for each property, again, implicitly telling users of your class that it is ok to set on but not the other.

If this is not the case then I suggest you provide a constructor which forces me to supply all three values. Yes, I can still use (null, null, null) , but you could check for that and throw an error.

Also, if PropertyA is dependent on PropertyB then either

A) Only one of them should have a setter, or

B) There should be logic in the setter of each to properly initialize the other after the value changes.

This is a design problem, not a language problem. You cannot force the initializer syntax to work differently than how it was spec'd.

Obj p = new Obj(1, 2, 3,...n); // too many properties to be pretty

Code isn't supposed to be 'pretty', it is supposed to work. Even then, a constructor which takes a few arguments is 'ugly'? Huh? Don't buy into the hipster nonsense, write code that works and works well.

The only way I could see this implemented is if there was some event (or equivalent) that was raised when the object initializer was completed. There is currently a Connect request for something to this effect.

Unfortunately, I didn't make the cut for .NET 4.5:

Thank you for your suggestion.

This is a great idea, and has the nice property that it doesn't add to the language surface - it just makes object initializers smarter. In principle that would probably make it a breaking change, but that is something we can look into.

Unfortunately we cannot add any more to the release we are currently building, so I am going to resolve as Won't fix for this release. However, I am capturing the suggestion on our list of features for future discussion.

Thanks again!

Mads Torgersen, C# Language PM

Maybe it'll make it's way into .NET 5+.

What about Code Contracts ?. This will assert not only that you assigned a value, but you could also specify valid ranges.

Or for check at runtime with debug builds only, you could use Debug.Assert(...) calls to achieve the same as above.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM