我想创建自己的EMailAddress类,其行为类似于字符串类.
所以我喜欢这样做
private EMailAddress _emailAddress = "Test@Test.com";
Run Code Online (Sandbox Code Playgroud)
代替
private EMailAddress _emailAddress = new EMailAddress("Test@Test.com");
Run Code Online (Sandbox Code Playgroud)
有没有办法实现我想要的,或者我需要使用第二种选择.由于字符串是密封的,我不能使用它,并且=运算符不能被重载所以我没有想法如何解决这个问题....
Tho*_*rin 30
您可以通过隐式转换:
public class EMailAddress
{
private string _address;
public EMailAddress(string address)
{
_address = address;
}
public static implicit operator EMailAddress(string address)
{
// While not technically a requirement; see below why this is done.
if (address == null)
return null;
return new EMailAddress(address);
}
}
Run Code Online (Sandbox Code Playgroud)
只有在转换中没有数据丢失时才应使用隐式转换.即便如此,我建议您谨慎使用此功能,因为它会使您的代码更难以阅读.
在此示例中,隐式运算符null在null传递字符串时返回.正如Jon Hanna正确评论的那样,让这两段代码表现不同是不可取的:
// Will assign null to the reference
EMailAddress x = null;
// Would create an EMailAddress object containing a null string
string s = null;
EMailAddress y = s;
Run Code Online (Sandbox Code Playgroud)
class EMailAddress
{
// ...other members
public static implicit operator EMailAddress (string address)
{
return new EMailAddress(address);
}
}
Run Code Online (Sandbox Code Playgroud)
但是,我建议谨慎使用.
我认为这个问题是关于在 C# 应用程序中创建类型安全的更一般问题的一个特定案例。我的示例是两种类型的数据:价格和重量。它们有不同的计量单位,因此永远不要尝试为重量分配价格,反之亦然。两者在封面下都是真正的十进制值。(我忽略了这样一个事实,即可能存在磅到公斤等的转换。)同样的想法可以应用于具有特定类型的字符串,如 EmailAddress 和 UserLastName。
使用一些相当样板的代码,您可以在特定类型之间进行显式转换或隐式转换:价格和重量,以及基础类型小数。
public class Weight
{
private readonly Decimal _value;
public Weight(Decimal value)
{
_value = value;
}
public static explicit operator Weight(Decimal value)
{
return new Weight(value);
}
public static explicit operator Decimal(Weight value)
{
return value._value;
}
};
public class Price {
private readonly Decimal _value;
public Price(Decimal value) {
_value = value;
}
public static explicit operator Price(Decimal value) {
return new Price(value);
}
public static explicit operator Decimal(Price value)
{
return value._value;
}
};
Run Code Online (Sandbox Code Playgroud)
使用“显式”运算符覆盖,可以使用这些类获得一组更严格的操作。每次从一种类型更改为另一种类型时,您都必须手动区分大小写。例如:
public void NeedsPrice(Price aPrice)
{
}
public void NeedsWeight(Weight aWeight)
{
}
public void NeedsDecimal(Decimal aDecimal)
{
}
public void ExplicitTest()
{
Price aPrice = (Price)1.23m;
Decimal aDecimal = 3.4m;
Weight aWeight = (Weight)132.0m;
// ok
aPrice = (Price)aDecimal;
aDecimal = (Decimal)aPrice;
// Errors need explicit case
aPrice = aDecimal;
aDecimal = aPrice;
//ok
aWeight = (Weight)aDecimal;
aDecimal = (Decimal) aWeight;
// Errors need explicit cast
aWeight = aDecimal;
aDecimal = aWeight;
// Errors (no such conversion exists)
aPrice = (Price)aWeight;
aWeight = (Weight)aPrice;
// Ok, but why would you ever do this.
aPrice = (Price)(Decimal)aWeight;
aWeight = (Weight)(Decimal)aPrice;
NeedsPrice(aPrice); //ok
NeedsDecimal(aPrice); //error
NeedsWeight(aPrice); //error
NeedsPrice(aDecimal); //error
NeedsDecimal(aDecimal); //ok
NeedsWeight(aDecimal); //error
NeedsPrice(aWeight); //error
NeedsDecimal(aWeight); //error
NeedsWeight(aWeight); //ok
}
Run Code Online (Sandbox Code Playgroud)
只需通过在代码中将“显式”替换为“隐式”,将“显式”运算符更改为“隐式”运算符,就可以在无需任何额外工作的情况下来回转换为底层 Decimal 类。这使得价格和重量表现得更像十进制,但您仍然无法将价格更改为重量。这通常是我正在寻找的类型安全级别。
public void ImplicitTest()
{
Price aPrice = 1.23m;
Decimal aDecimal = 3.4m;
Weight aWeight = 132.0m;
// ok implicit cast
aPrice = aDecimal;
aDecimal = aPrice;
// ok implicit cast
aWeight = aDecimal;
aDecimal = aWeight;
// Errors
aPrice = aWeight;
aWeight = aPrice;
NeedsPrice(aPrice); //ok
NeedsDecimal(aPrice); //ok
NeedsWeight(aPrice); //error
NeedsPrice(aDecimal); //ok
NeedsDecimal(aDecimal); //ok
NeedsWeight(aDecimal); //ok
NeedsPrice(aWeight); //error
NeedsDecimal(aWeight); //ok
NeedsWeight(aWeight); //ok
}
Run Code Online (Sandbox Code Playgroud)
为 String 而不是 Decimal 执行此操作时。我喜欢 Thorarin 关于检查 null 并在转换中将 null 传回的答案。例如
public static implicit operator EMailAddress(string address)
{
// Make
// EmailAddress myvar=null
// and
// string aNullString = null;
// EmailAddress myvar = aNullString;
// give the same result.
if (address == null)
return null;
return new EMailAddress(address);
}
Run Code Online (Sandbox Code Playgroud)
要将这些类用作 Dictionary 集合的键,您还需要实现 Equals、GetHashCode、运算符 == 和运算符 !=
为了让这一切变得更容易,我创建了一个可以扩展的 ValueType 类,ValueType 类为除转换运算符之外的所有内容调用基类型。