La Surcharge d'opérateur avec Interface de Base de la Programmation en C#

Fond

Je suis en utilisant l'interface de programmation basé sur un projet en cours et ont rencontré un problème lors de la surcharge des opérateurs (plus précisément de l'Égalité et de l'Inégalité des opérateurs).


Hypothèses

  • Je suis à l'aide de C# 3.0, .NET 3.5 et Visual Studio 2008

Mise à JOUR - L'Hypothèse Suivante a été Faux!

  • Exigeant que toutes les comparaisons à utilisation Égale, plutôt que de l'opérateur== est pas une solution viable, en particulier lors du passage de vos types de bibliothèques (comme les Collections).

La raison pour laquelle j'étais inquiète au sujet de l'obligation est Égale à utiliser plutôt que l'opérateur== est que je ne pouvais pas trouver n'importe où dans le .NET des lignes directrices qu'il a déclaré qu'il utiliserait est Égal plutôt que l'opérateur==, ou même suggérer. Cependant, après re-lecture Lignes directrices pour l'Impérieuse d'égal à Égal et de l'Opérateur== j'ai trouvé ceci:

Par défaut, l'opérateur == tests de référence de l'égalité de déterminer si deux références indiquent le même objet. Par conséquent, les types de référence n'ont pas à mettre en œuvre l'opérateur == pour obtenir cette fonctionnalité. Quand un type est immuable, qui est, les données contenues dans l'instance ne peut pas être changé, la surcharge de l'opérateur == pour comparer la valeur de l'égalité au lieu de référence de l'égalité peut être utile parce que, comme des objets immuables, ils peuvent être considérés de la même aussi longtemps qu'ils ont la même valeur. Ce n'est pas une bonne idée de remplacer l'opérateur == non immuable types.

et ce Equatable Interface

La IEquatable interface est utilisée par générique des objets de collection tels que le Dictionnaire, la Liste et les LinkedList lors de l'essai pour l'égalité dans les méthodes telles que Contient, IndexOf, LastIndexOf, et Retirez-la. Il devrait être mis en œuvre pour n'importe quel objet qui peut être stocké dans une collection générique.


Contraintes

  • Aucune solution ne doit pas nécessiter de casting les objets de leurs interfaces à leurs types de béton.

Problème

  • Quand jamais les deux côtés de l'opérateur== sont une interface, aucun opérateur== surcharge de la signature de la méthode de la sous-jacentes types de béton match et donc la valeur par défaut de l'Objet de l'opérateur== méthode sera appelée.
  • En cas de surcharge d'un opérateur sur une classe, au moins l'un des paramètres de l'opérateur binaire doit être du type contenant, sinon une erreur de compilateur est produite (Erreur BC33021 http://msdn.microsoft.com/en-us/library/watt39ff.aspx)
  • Il n'est pas possible de spécifier la mise en œuvre sur une interface

Voir le Code et de Sortie ci-dessous montrant le problème.


Question

Comment voulez-vous assurer la surcharge de l'opérateur pour vos classes lors de l'utilisation de l'interface de base de la programmation?


Références

Opérateur = = (Référence C#)

Prédéfinis pour différents types de valeurs, l'opérateur d'égalité (==) retourne true si les valeurs de ses opérandes sont égaux, sinon false. Pour les types de référence autres que string, == retourne true si les deux opérandes font référence au même objet. Pour le type de chaîne, == compare les valeurs des chaînes de caractères.


Voir Aussi


Code

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.");
}
}
}
}

Sortie

Address operator== overload called
Equal with both sides cast.
  • Pouvez-vous revenir sur votre deuxième hypothèse? Collection les classes à utiliser .Méthode Equals ().
  • +1 pour la clarté et les détails en question.
  • kvb - j'ai mis à jour ma deuxième hypothèse, et après la lecture de Jean de la réponse et un peu plus de MSDN docs, l'hypothèse est fausse. J'ai noté ci-dessus. Merci! Cyril, merci de vous!