Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I enforce that fields in a POCO are only ever set in a type initialiser?

If I have a POCO such as this:

[Poco]
public class MyPoco
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Address { get; set; }
}

... and it's initialised like this:

new MyPoco { FirstName = "Joe", LastName="Bloggs", Address="123 Abc St." }

Can I, using CQL in NDepend, ensure that the properties are only ever set using the object initialiser as above, and not separately.

I'm trying to catch code like this:

myPoco.FirstName="John";
doSomething(myPoco);

... I don't want people to set properties on an existing POCO. I understand I can make the setters private, but I don't like passing in all the properties in a constructor because you end up with a signature such as MyPoco(string, string, string) - making it easier to misalign the parameters (easier than using the object initialiser syntax)

So, I want to catch this using NDepend. Here's the start of my CQL query:

from f in JustMyCode.Fields.Where(f=>
   f.ParentType.HasAttribute ("JetBrains.Annotations.PocoAttribute".AllowNoMatch())) 
       where f.MethodsAssigningMe [I'M STUMPED HERE]

It looks like I can analyse the method setting the property of a POCO, but I need to go one step lower and examing the code block to see if it's in an object initialiser block.

Is this possible?

like image 338
Steve Dunn Avatar asked Dec 11 '25 19:12

Steve Dunn


1 Answers

I don't know whether you can do this in CQL, although even if you can't, you might well be able to do it with Roslyn.

However, you might want to consider using a builder pattern instead:

var poco = new MyPoco.Builder { FirstName = "Joe",
                                LastName="Bloggs",
                                Address="123 Abc St." }.Build();

Now the poco itself can be immutable, but the builder can have the properties set wherever you like.

Heck, if you're a fan of implicit conversions you could even have an implicit conversion from the builder to the poco:

MyPoco poco = new MyPoco.Builder { FirstName = "Joe",
                                   LastName="Bloggs",
                                   Address="123 Abc St." };

While I'm all for tools verifying proper coding where it's not possible to design a type to avoid it being misused to start with, I'd prefer to have an idiot-proof API to start with :)

Also note that with named arguments in C# 4, even the constructor version can be made clear:

var poco = new MyPoco(firstName: "Joe",
                      lastName: "Bloggs",
                      address: "123 Abc St.");

but of course that still allows people to write it without the named arguments...

like image 125
Jon Skeet Avatar answered Dec 14 '25 13:12

Jon Skeet



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!