操作员负载过重,与基于接口编程在C#
-
05-09-2019 - |
题
背景
我使用的接口编程上目前项目,并已遇到一个问题时,载运营商(具体的平等和不平等的经营者).
假设
- 我使用的C#3.0,.净3.5和Visual Studio2008
更新以下的假设是假的!
- 要求所有的比较使用的平等,而不是操作者==不是一种可行的解决方案,特别是当通过你的类型文库(诸如集的).
我之所以感到关切的是关于需要等于将使用,而不是操作者==的是,我找不到任何地方。净的准则,它指出,它将使用等,而不是操作者==或者甚至建议。然而,在重新阅读 准则》压倒一切的等和操作人员== 我发现了这个:
默认情况下,操作者==试验供参考的平等,通过确定是否两个参考文献表示同样的对象。因此,参照类型没有实施操作员==为了获得这一功能。当一个类型是不可改变的,也就是说,数据中包含的实例不能更改,载操作员==比较价值的平等,而不是参照平等可能是有用的,因为不可改变的对象,他们可以被认为是相同的,只要他们有同样的价值。它不是一个好主意,以复盖操作者==非不可改变类型。
和这个 Equatable口
这就不能修改的接口是使用通用收集对象,例如字典、列表和链表进行测试时,为女平等等方法包含个,LastIndexOf,并删除。它应该是实现任何目的,可能被存储在一个通用的集合。
约束
- 任何解决方案必须不需要铸造的对象,他们的接口到他们的具体类型。
的问题
- 当双方的操作人员==是一个界面,没有运营商==超载方法的签名从基础的具体类型的匹配,从而默认对象操作员==的方法将被称为。
- 当载有操作上的一类,至少有一个参数的二进制的操作员必须包含类型,否则一个编译器产生错误(错误BC33021 http://msdn.microsoft.com/en-us/library/watt39ff.aspx)
- 它不可能指定的执行上的一个接口
看到码和输出下面表明这一问题。
的问题
你怎么提供适当操作过载于您的课程时使用的接口基础编程?
参考文献
对于预先定义的价值的类型、平等操作员(==)返回真正的如果它的操作数都是平等的,假。为参照其他类型比string,==返回真正的如果它的两个操作数指相同的对象。为串的类型,==比较的价值观。
也参看
代码
using System;
namespace OperatorOverloadsWithInterfaces
{
public interface IAddress : IEquatable<IAddress>
{
string StreetName { get; set; }
string City { get; set; }
string State { get; set; }
}
public class Address : IAddress
{
private string _streetName;
private string _city;
private string _state;
public Address(string city, string state, string streetName)
{
City = city;
State = state;
StreetName = streetName;
}
#region IAddress Members
public virtual string StreetName
{
get { return _streetName; }
set { _streetName = value; }
}
public virtual string City
{
get { return _city; }
set { _city = value; }
}
public virtual string State
{
get { return _state; }
set { _state = value; }
}
public static bool operator ==(Address lhs, Address rhs)
{
Console.WriteLine("Address operator== overload called.");
// If both sides of the argument are the same instance or null, they are equal
if (Object.ReferenceEquals(lhs, rhs))
{
return true;
}
return lhs.Equals(rhs);
}
public static bool operator !=(Address lhs, Address rhs)
{
return !(lhs == rhs);
}
public override bool Equals(object obj)
{
// Use 'as' rather than a cast to get a null rather an exception
// if the object isn't convertible
Address address = obj as Address;
return this.Equals(address);
}
public override int GetHashCode()
{
string composite = StreetName + City + State;
return composite.GetHashCode();
}
#endregion
#region IEquatable<IAddress> Members
public virtual bool Equals(IAddress other)
{
// Per MSDN documentation, x.Equals(null) should return false
if ((object)other == null)
{
return false;
}
return ((this.City == other.City)
&& (this.State == other.State)
&& (this.StreetName == other.StreetName));
}
#endregion
}
public class Program
{
static void Main(string[] args)
{
IAddress address1 = new Address("seattle", "washington", "Awesome St");
IAddress address2 = new Address("seattle", "washington", "Awesome St");
functionThatComparesAddresses(address1, address2);
Console.Read();
}
public static void functionThatComparesAddresses(IAddress address1, IAddress address2)
{
if (address1 == address2)
{
Console.WriteLine("Equal with the interfaces.");
}
if ((Address)address1 == address2)
{
Console.WriteLine("Equal with Left-hand side cast.");
}
if (address1 == (Address)address2)
{
Console.WriteLine("Equal with Right-hand side cast.");
}
if ((Address)address1 == (Address)address2)
{
Console.WriteLine("Equal with both sides cast.");
}
}
}
}
输出
Address operator== overload called
Equal with both sides cast.
解决方案
简短的回答:我觉得你的第二个假设可能是有缺陷的。 Equals()
是正确的方式来检查 语义上的平等 两个对象,不 operator ==
.
只要回答:过载决议为运营商是 进行汇编时,无法运行时间.
除非编译器可以明确地知道类型的对象是施加操作者,它不会编译。由于编译器不能确保一个 IAddress
要的东西,都有一个复盖 ==
定义,回落到默认的 operator ==
执行情况 System.Object
.
看看这个更清楚,试图限定一个 operator +
对于 Address
并添加两个 IAddress
实例。 除非你明确地浇铸 Address
, 它将无法编译。为什么?因为编译器不能告诉一个特别的 IAddress
是一个 Address
, 和没有默认的 operator +
实现的回落到在 System.Object
.
一部分的你的挫折可能源自这一事实, Object
实现一个 operator ==
, 和一切的是 Object
, ,因此编译器可以成功地解决操作的喜欢 a == b
对于所有种类型。当你推翻了 ==
, 你期望看到的同样的行为,但不,这是因为最好的匹配的编译器可以找到是原来的 Object
执行情况。
要求所有的比较使用的平等,而不是操作者==不是一种可行的解决方案,特别是当通过你的类型文库(诸如集的).
在我看来,这正是你应该做的。 Equals()
是正确的方式来检查 语义上的平等 两个对象。 有时候,语义上的平等只是参考平等,在这种情况下你不需要改变任何东西。在其他情况下,如在例,只复盖 Equals
当你需要一个更强大的平等,合同于参照的平等。例如,你可能想要考虑两个 Persons
等如果他们有相同的社会安全号码,或者两个 Vehicles
等如果他们有相同的VIN。
但 Equals()
和 operator ==
是不一样的东西。每当你需要复盖 operator ==
, 你应该复盖 Equals()
, 但几乎没有其他方式。 operator ==
更多的是语法的便利。一些CLR语言(例如视觉Basic.NET)甚至不允许您替代的平等操作员。
其他提示
我们碰到了同样的问题,并发现一个很好的解决方案:Resharper定义的模式。
我们构成我们所有的用户使用全球共同模式编录在除了他们自己的,把它放到SVN,以便它可以进行版本控制和更新每个人。
目录中包含的所有模式称为是错误的,在我们的系统:
$i1$ == $i2$
(其中i1和i2是 表情 我们的界面类型,或者衍生的。
替换模式
$i1$.Equals($i2$)
和严重程度是"显示为错误"。
同样,我们有 $i1$ != $i2$
希望这会有所帮助。P.S.全球目录的特点是在Resharper6.1(EAP),将被标记为最后的很快。
更新:我申请了 Resharper问题 标记所有接口'=='a警告,除非它是比较为空。请投票,如果你认为这是一个有价值的特征。
Update2:Resharper还有[CannotApplyEqualityOperator]属性,可以帮助。