我可以强制POCO中的字段只在类型初始化器中设置吗?

本文关键字:类型 初始化 设置 POCO 字段 我可以 | 更新日期: 2023-09-27 18:09:44

如果我有这样一个POCO:

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

…它是这样初始化的:

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

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

我正在尝试捕获这样的代码:

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

…我不希望人们在现有的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]

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

这可能吗?

我可以强制POCO中的字段只在类型初始化器中设置吗?

我不知道你是否可以在CQL中做到这一点,尽管即使你不能,你也可以用Roslyn做到这一点。

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

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

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

如果你是隐式转换的粉丝,你甚至可以有一个从构建器到poco的隐式转换:

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

虽然我完全支持工具来验证正确的编码,但在不可能设计类型以避免它被误用的情况下,我更喜欢有一个傻瓜式的API来开始:)

还要注意,在c# 4中使用命名参数,甚至构造函数版本也可以明确:

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

但是当然,仍然允许的人不用命名参数来写它。