我是否可以强制执行POCO中的字段只能在类型初始化器中设置?

Ste*_*unn 3 c# code-analysis ndepend cql poco

如果我有这样的POCO:

[Poco]
public class MyPoco
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Address { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

......它的初始化如下:

new MyPoco { FirstName = "Joe", LastName="Bloggs", Address="123 Abc St." }
Run Code Online (Sandbox Code Playgroud)

我是否可以在NDepend中使用CQL,确保只使用上面的对象初始化程序设置属性,而不是单独设置.

我正试图抓住这样的代码:

myPoco.FirstName="John";
doSomething(myPoco);
Run Code Online (Sandbox Code Playgroud)

...我不希望人们在现有的POCO上设置属性.我理解我可以创建setter private,但我不喜欢传入构造函数中的所有属性,因为你最终会得到一个签名MyPoco(string, string, string)- 使得更容易错位参数(比使用对象初始化语法更容易)

所以,我想用NDepend来捕获它.这是我的CQL查询的开始:

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

看起来我可以分析设置POCO属性的方法,但是我需要更低一步并检查代码块以查看它是否在对象初始化块中.

这可能吗?

Jon*_*eet 5

我不知道你是否可以在CQL中做到这一点,虽然即使你做不到,你也许可以用Roslyn做到这一点.

但是,您可能需要考虑使用构建器模式:

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

现在poco本身可以是不可变的,但构建器可以在任何你喜欢的地方设置属性.

哎呀,如果你是隐式转换的粉丝,你可能甚至有从建设者到POCO的隐式转换:

MyPoco poco = new MyPoco.Builder { FirstName = "Joe",
                                   LastName="Bloggs",
                                   Address="123 Abc St." };
Run Code Online (Sandbox Code Playgroud)

虽然我所有的工具都是为了验证正确的编码而不能设计一种类型来避免它被误用,但我更喜欢开始使用一种防止傻瓜的API :)

另请注意,使用C#4中的命名参数,甚至构造函数版本也可以清楚:

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

但当然,仍然允许人们在没有命名参数的情况下编写它...