静态隐式运算符

我最近发现了这样的代码:

 public static implicit operator XElement(XmlBase xmlBase)
{
return xmlBase.Xml;
}

static implicit operator是什么意思?

67919 次浏览

这样一个隐式操作符意味着你可以隐式地将XmlBase转换为XElement

XmlBase xmlBase = WhatEverGetTheXmlBase();
XElement xelement = xmlBase;
//no explicit convert here like: XElement xelement = (XElement)xmlBase;

它是一个隐式转换操作符(与显式操作符相反,显式操作符需要(type)转换语法)

这是一个< >强转换操作符< / >强。这意味着你可以写这样的代码:

XmlBase myBase = new XmlBase();
XElement myElement = myBase;

编译器不会报错!在运行时,将执行转换运算符——将myBase作为参数传入,并返回有效的XElement作为结果。

这是你作为开发者告诉编译器的一种方式:

尽管这看起来像是两种完全不相关的类型,但实际上有一种方法可以将其中一种转换为另一种;让我来处理如何做这件事的逻辑。”

另一个有趣的用法是(Unity检查对象(因此是MonoBehavior的实例)是否为空):

public static implicit operator bool (CustomClass c)
{
return c != null;
}

注意,代码必须在类内部(在本例中为CustomClass)。这样你就可以这样做:

void Method ()
{
CustomClass c1 = null;
CustomClass c2 = new CustomClass ();


bool b1 = c1; // is false
bool b2 = c2; // is true


if (!c1 && c2)
{
// Do stuff
}
}

显然,最臭名昭著的使用可能是使用它将一个类转换为另一个类。但是将它们与基本类型一起使用也值得考虑……我很少看到有人提到它。

我的意见。

这在单元测试将与构建器模式一起使用的不可变实体时非常有用。

假设您以不可变的方式定义了Employee域对象。我们通常在我想坚持DDD风格.;

public class Employee
{
public Employee(int id, string firstname, string lastname, DateTime birthdate, string street)
{
this.ID = id;
this.FirstName = firstname;
this.LastName = lastname;
this.BirthDate = birthdate;
this.Street = street;
}


public int ID { get; private set; }
public string FirstName { get; private set; }
public string LastName { get; private set; }
public DateTime BirthDate { get; private set; }
public string Street { get; private set; }


public string getFullName()
{
return this.FirstName + " " + this.LastName;
}


public int getAge()
{
DateTime today = DateTime.Today;
int age = today.Year - BirthDate.Year;
    

if (BirthDate > today.AddYears(-age))
age--;


return age;
}
}

现在您可以拥有如下所示的雇员构建器(在测试项目内部)。注意到最后,我们有了这个隐式运算符。

public class EmployeeBuilder
{
private int id = 1;
private string firstname = "first";
private string lastname = "last";
private DateTime birthdate = DateTime.Today;
private string street = "street";
public Employee Build()
{
return new Employee(id, firstname, lastname, birthdate, street);
}
public EmployeeBuilder WithFirstName(string firstname)
{
this.firstname = firstname;
return this;
}
public EmployeeBuilder WithLastName(string lastname)
{
this.lastname = lastname;
return this;
}
public EmployeeBuilder WithBirthDate(DateTime birthdate)
{
this.birthdate = birthdate;
return this;
}
public EmployeeBuilder WithStreet(string street)
{
this.street = street;
return this;
}
public static implicit operator Employee(EmployeeBuilder instance)
{
return instance.Build();
}
}

现在您可以拥有如下所示的员工测试类。

public class EmployeeTest
{
[Test]
public void GetFullNameReturnsCombination()
{
// Arrange
Employee emp = new EmployeeBuilder().WithFirstName("Vivek").WithLastName("Koppula");
// Act
string fullname = emp.getFullName();
// Assert
Assert.That(fullname, Is.EqualTo("Vivek Koppula"));
}


[Test]
public void GetAgeReturnsCorrectValue() {
// Arrange
Employee emp = new EmployeeBuilder().WithBirthDate(new DateTime(1983, 1,1));
// Act
int age = emp.getAge();
// Assert
Assert.That(age, Is.EqualTo(DateTime.Today.Year - 1983));
}
}

这使得编写单元测试更容易,因为我们可以用所需的参数构造雇员。

例如,在第一个测试中,我们只关心名字和姓氏。对于第一种情况,我们不需要被年龄和街道所困扰。

第二种情况也是一样,我们只关心年龄。

文章引用。

  1. flexible-and- expression -unit-tests-with-the-builder-pattern
  2. improve-tests-with-the-builder-pattern-for-test-data