C# 类构造函数,该构造函数要求命名所有参数和所有参数
有没有一种方法可以定义我的类,这样该类的调用者就会得到编译时错误,除非他们指定了该类的每个属性,并附加了参数传递的命名约束 假设我有这个界面:C# 类构造函数,该构造函数要求命名所有参数和所有参数,c#,initialization,C#,Initialization,有没有一种方法可以定义我的类,这样该类的调用者就会得到编译时错误,除非他们指定了该类的每个属性,并附加了参数传递的命名约束 假设我有这个界面: public interface IPerson { string FirstName {get;} string MiddleName { get; } string LastName { get;} } 这些课程: public class PersonNeedAllProperties : IPerson { pu
public interface IPerson
{
string FirstName {get;}
string MiddleName { get; }
string LastName { get;}
}
这些课程:
public class PersonNeedAllProperties : IPerson
{
public string FirstName { get; private set;} // ideally readonly
public string MiddleName { get; private set;}
public string LastName { get; private set;}
public PersonNeedAllProperties(
string firstName,
string lastName,
string middleName)
{
this.FirstName = firstName;
this.MiddleName = middleName;
this.LastName = lastName;
}
}
public class PersonCanNamePropertiesButNotSadlyNotRequired : IPerson
{
public string FirstName { get; set;} // ideally readonly
public string MiddleName { get; set;}
public string LastName { get; set;}
}
那么这些imho的问题如下:
var p1 = new PersonNeedAllProperties("lastName", "firstName", "middle");
// woops wrong order because not named.
var p2 = new PersonCanNamePropertiesButNotSadlyNotRequired()
{
FirstName = "firstName",
LastName = "lastName"
}; // woops forgot all about the middlename.
有没有一种方法可以获得一个初始化类似于person 2但需要命名所有属性的简单POCO对象
这是上面的问题:回答你的问题不,这是不可能的 你要求能够强迫两件事:
- a) 强制设置所有属性
- b) 强制命名属性
public abstract class Person
{
public abstract string FirstName {get; protected set; }
public abstract string MiddleName { get; protected set; }
public abstract string LastName { get; protected set; }
public Person(string firstName, string middleName, string lastName){
FirstName = firstName;
MiddleName = middleName;
LastName = lastName;
}
}
public class PersonNeedAllProperties : Person
{
public override string FirstName{get; protected set;}
public override string MiddleName{get; protected set;}
public override string LastName{get; protected set;}
public PersonNeedAllProperties(
string firstName,
string lastName,
string middleName)
: base(firstName, lastName, middleName)
{
}
}
b) 要强制按名称设置属性,不能在构造函数中指定它们
旁注:可以向构造函数提供命名参数,但不能强制这些参数,即var person=new person(firstName:'John',lastName:'Doe',middleName:'a')
最接近的方法是将属性标记为只读(私有集),并像在PersonneAllProperties
类中那样,仅从构造函数中设置属性
可能是一种可行的替代方案的东西被称为。
这将有一个额外的类负责构造对象,但您仍然无法得到编译时错误,只能得到运行时错误。回答您的问题否,这是不可能的 你要求能够强迫两件事:
- a) 强制设置所有属性
- b) 强制命名属性
public abstract class Person
{
public abstract string FirstName {get; protected set; }
public abstract string MiddleName { get; protected set; }
public abstract string LastName { get; protected set; }
public Person(string firstName, string middleName, string lastName){
FirstName = firstName;
MiddleName = middleName;
LastName = lastName;
}
}
public class PersonNeedAllProperties : Person
{
public override string FirstName{get; protected set;}
public override string MiddleName{get; protected set;}
public override string LastName{get; protected set;}
public PersonNeedAllProperties(
string firstName,
string lastName,
string middleName)
: base(firstName, lastName, middleName)
{
}
}
b) 要强制按名称设置属性,不能在构造函数中指定它们
旁注:可以向构造函数提供命名参数,但不能强制这些参数,即var person=new person(firstName:'John',lastName:'Doe',middleName:'a')
最接近的方法是将属性标记为只读(私有集),并像在PersonneAllProperties
类中那样,仅从构造函数中设置属性
可能是一种可行的替代方案的东西被称为。
这将有一个额外的类负责构造对象,但您仍然无法得到编译时错误,只能得到运行时错误。有一种可怕的方法几乎可以实现这一点。不是按名字而是按类型。我不推荐。但是有一种可怕的方法。我说过这很可怕吗 “计算机科学中的任何问题都可以通过增加一层间接性来解决”——惠勒 使每个属性都具有各自不同的类型。现在不能以错误的顺序传递它们,否则编译器会告诉您传递了无效的类型
public class FirstName
{
string Value { get; set; }
}
public class MiddleName
{
string Value { get; set; }
}
public class LastName
{
string Value { get; set; }
}
public interface IPerson
{
FirstName FirstName {get;}
MiddleName MiddleName { get; }
LastName LastName { get;}
}
public class PersonNeedAllProperties : IPerson
{
public FirstName FirstName { get; private set;} // ideally readonly
public MiddleName MiddleName { get; private set;}
public LastName LastName { get; private set;}
public PersonNeedAllProperties(
FirstName firstName,
MiddleName lastName,
LastName middleName)
{
this.FirstName = firstName;
this.MiddleName = middleName;
this.LastName = lastName;
}
}
有一种可怕的方法几乎可以强制执行。不是按名字而是按类型。我不推荐。但是有一种可怕的方法。我说过这很可怕吗 “计算机科学中的任何问题都可以通过增加一层间接性来解决”——惠勒 使每个属性都具有各自不同的类型。现在不能以错误的顺序传递它们,否则编译器会告诉您传递了无效的类型
public class FirstName
{
string Value { get; set; }
}
public class MiddleName
{
string Value { get; set; }
}
public class LastName
{
string Value { get; set; }
}
public interface IPerson
{
FirstName FirstName {get;}
MiddleName MiddleName { get; }
LastName LastName { get;}
}
public class PersonNeedAllProperties : IPerson
{
public FirstName FirstName { get; private set;} // ideally readonly
public MiddleName MiddleName { get; private set;}
public LastName LastName { get; private set;}
public PersonNeedAllProperties(
FirstName firstName,
MiddleName lastName,
LastName middleName)
{
this.FirstName = firstName;
this.MiddleName = middleName;
this.LastName = lastName;
}
}
不,接口不是设计成这样的 接口确保实现它的类将在接口中声明所有元素。但没有就如何实现这些目标发表任何声明 您可以使用带有自定义构造函数的抽象类来完成所需的任务
public abstract class Person
{
public abstract string FirstName {get; protected set; }
public abstract string MiddleName { get; protected set; }
public abstract string LastName { get; protected set; }
public Person(string firstName, string middleName, string lastName){
FirstName = firstName;
MiddleName = middleName;
LastName = lastName;
}
}
public class PersonNeedAllProperties : Person
{
public override string FirstName{get; protected set;}
public override string MiddleName{get; protected set;}
public override string LastName{get; protected set;}
public PersonNeedAllProperties(
string firstName,
string lastName,
string middleName)
: base(firstName, lastName, middleName)
{
}
}
自定义构造函数强制您完成子类中的名称
您可以将这个答案与使用类而不是字符串作为名称(firstName、middleName、lastName)来模拟命名参数的答案结合起来
您需要了解此方法的局限性,在C语言中,您不能从多个类继承,因此,如果您决定实现此解决方案,则需要记住此限制。不,接口的设计不是这样的 接口确保实现它的类将在接口中声明所有元素。但没有就如何实现这些目标发表任何声明 您可以使用带有自定义构造函数的抽象类来完成所需的任务
public abstract class Person
{
public abstract string FirstName {get; protected set; }
public abstract string MiddleName { get; protected set; }
public abstract string LastName { get; protected set; }
public Person(string firstName, string middleName, string lastName){
FirstName = firstName;
MiddleName = middleName;
LastName = lastName;
}
}
public class PersonNeedAllProperties : Person
{
public override string FirstName{get; protected set;}
public override string MiddleName{get; protected set;}
public override string LastName{get; protected set;}
public PersonNeedAllProperties(
string firstName,
string lastName,
string middleName)
: base(firstName, lastName, middleName)
{
}
}
自定义构造函数强制您完成子类中的名称
您可以将这个答案与使用类而不是字符串作为名称(firstName、middleName、lastName)来模拟命名参数的答案结合起来
您需要了解此方法的局限性,在C中,您不能从多个类继承,因此,如果您决定实现此解决方案,则需要记住此限制。这可以通过嵌套类实现,我想:
public interface IPerson
{
string FirstName { get; }
string MiddleName { get; }
string LastName { get; }
}
public class Person : IPerson
{
public string FirstName { get; private set; }
public string MiddleName { get; private set; }
public string LastName { get; private set; }
//Make sure the parameterless constructor is private
private Person() { }
private Person(string first, string middle, string last)
{
this.FirstName = first;
this.MiddleName = middle;
this.LastName = last;
}
public class Builder
{
private Person person = new Person();
public Builder WithFirstName(string first)
{
person.FirstName = first;
return this;
}
public Builder WithMiddleName(string middle)
{
person.MiddleName = middle;
return this;
}
public Builder WithLastName(string last)
{
person.LastName = last;
return this;
}
public IPerson Build()
{
if (person.FirstName != null
&& person.MiddleName != null
&& person.LastName != null)
return person;
throw new Exception("Cannot build person because reasons...");
}
}
}
然后按如下方式使用:
var person = new Person.Builder()
.WithFirstName("Rob")
.WithMiddleName("<I have no middle name>")
.WithLastName("Janssen")
.Build();
编辑:废话;我没有注意到编译时错误的其他要求 但是,这会“强制”您设置所有3个必填字段,并“强制”您使用
With…
方法“命名”字段,这使得很难混淆值,并且允许您按照所需的顺序指定值。它还可以防止您自己实例化一个人
,并允许您拥有自己的私有se