C # Etend le type de tableau pour surcharger les opérateurs
-
05-07-2019 - |
Question
J'aimerais créer ma propre classe en étendant le tableau d'ints. Est-ce possible? Ce dont j’ai besoin, c’est un tableau d’ints qui peut être ajouté avec "+". opérateur à un autre tableau (chaque élément ajouté à chacun), et comparé par "==", afin qu'il puisse (espérons-le) être utilisé comme clé dans le dictionnaire.
Le problème est que je ne veux pas implémenter toute l'interface IList dans ma nouvelle classe, mais seulement ajouter ces deux opérateurs à la classe de tableau existante.
J'essaie de faire quelque chose comme ça:
class MyArray : Array<int>
Mais ça ne marche pas comme ça évidemment;).
Désolé si je ne sais pas trop mais je cherche une solution depuis des heures ...
MISE À JOUR:
J'ai essayé quelque chose comme ça:
class Zmienne : IEquatable<Zmienne>
{
public int[] x;
public Zmienne(int ilosc)
{
x = new int[ilosc];
}
public override bool Equals(object obj)
{
if (obj == null || GetType() != obj.GetType())
{
return false;
}
return base.Equals((Zmienne)obj);
}
public bool Equals(Zmienne drugie)
{
if (x.Length != drugie.x.Length)
return false;
else
{
for (int i = 0; i < x.Length; i++)
{
if (x[i] != drugie.x[i])
return false;
}
}
return true;
}
public override int GetHashCode()
{
int hash = x[0].GetHashCode();
for (int i = 1; i < x.Length; i++)
hash = hash ^ x[i].GetHashCode();
return hash;
}
}
Ensuite, utilisez-le comme ceci:
Zmienne tab1 = new Zmienne(2);
Zmienne tab2 = new Zmienne(2);
tab1.x[0] = 1;
tab1.x[1] = 1;
tab2.x[0] = 1;
tab2.x[1] = 1;
if (tab1 == tab2)
Console.WriteLine("Works!");
Et aucun effet. Malheureusement, je ne suis pas doué pour les interfaces et les méthodes contraignantes :(. Pour ce qui est de la raison, j'essaie de le faire. J'ai quelques équations telles que:
x1 + x2 = 0,45
x1 + x4 = 0.2
x2 + x4 = 0,11
Il y en a beaucoup plus, et je dois par exemple ajouter la première équation à la seconde et rechercher dans toutes les autres pour savoir s'il en existe une qui corresponde à la combinaison de x'es, ce qui entraîne l'ajout.
Peut-être que je vais dans la mauvaise direction?
La solution
Pour un type unique, il est assez facile à encapsuler, comme ci-dessous. Notez qu'en tant que clé, vous souhaitez également la rendre immuable. Si vous souhaitez utiliser des génériques, cela devient plus difficile (demandez plus d'informations):
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
static class Program {
static void Main() {
MyVector x = new MyVector(1, 2, 3), y = new MyVector(1, 2, 3),
z = new MyVector(4,5,6);
Console.WriteLine(x == y); // true
Console.WriteLine(x == z); // false
Console.WriteLine(object.Equals(x, y)); // true
Console.WriteLine(object.Equals(x, z)); // false
var comparer = EqualityComparer<MyVector>.Default;
Console.WriteLine(comparer.GetHashCode(x)); // should match y
Console.WriteLine(comparer.GetHashCode(y)); // should match x
Console.WriteLine(comparer.GetHashCode(z)); // *probably* different
Console.WriteLine(comparer.Equals(x,y)); // true
Console.WriteLine(comparer.Equals(x,z)); // false
MyVector sum = x + z;
Console.WriteLine(sum);
}
}
public sealed class MyVector : IEquatable<MyVector>, IEnumerable<int> {
private readonly int[] data;
public int this[int index] {
get { return data[index]; }
}
public MyVector(params int[] data) {
if (data == null) throw new ArgumentNullException("data");
this.data = (int[])data.Clone();
}
private int? hash;
public override int GetHashCode() {
if (hash == null) {
int result = 13;
for (int i = 0; i < data.Length; i++) {
result = (result * 7) + data[i];
}
hash = result;
}
return hash.GetValueOrDefault();
}
public int Length { get { return data.Length; } }
public IEnumerator<int> GetEnumerator() {
for (int i = 0; i < data.Length; i++) {
yield return data[i];
}
}
IEnumerator IEnumerable.GetEnumerator() {
return GetEnumerator();
}
public override bool Equals(object obj)
{
return this == (obj as MyVector);
}
public bool Equals(MyVector obj) {
return this == obj;
}
public override string ToString() {
StringBuilder sb = new StringBuilder("[");
if (data.Length > 0) sb.Append(data[0]);
for (int i = 1; i < data.Length; i++) {
sb.Append(',').Append(data[i]);
}
sb.Append(']');
return sb.ToString();
}
public static bool operator ==(MyVector x, MyVector y) {
if(ReferenceEquals(x,y)) return true;
if(ReferenceEquals(x,null) || ReferenceEquals(y,null)) return false;
if (x.hash.HasValue && y.hash.HasValue && // exploit known different hash
x.hash.GetValueOrDefault() != y.hash.GetValueOrDefault()) return false;
int[] xdata = x.data, ydata = y.data;
if(xdata.Length != ydata.Length) return false;
for(int i = 0 ; i < xdata.Length ; i++) {
if(xdata[i] != ydata[i]) return false;
}
return true;
}
public static bool operator != (MyVector x, MyVector y) {
return !(x==y);
}
public static MyVector operator +(MyVector x, MyVector y) {
if(x==null || y == null) throw new ArgumentNullException();
int[] xdata = x.data, ydata = y.data;
if(xdata.Length != ydata.Length) throw new InvalidOperationException("Length mismatch");
int[] result = new int[xdata.Length];
for(int i = 0 ; i < xdata.Length ; i++) {
result[i] = xdata[i] + ydata[i];
}
return new MyVector(result);
}
}
Autres conseils
Il n'est pas autorisé à étendre la classe array, voir la référence: http : //msdn.microsoft.com/en-us/library/system.array.aspx
Vous pouvez soit implémenter IList (qui a les méthodes de base), soit encapsuler un tableau dans votre classe et fournir des opérateurs de conversion.
Faites-moi savoir si vous avez besoin de plus de détails.
Ne pouvez-vous pas simplement utiliser la classe List? Cela fait déjà ce que vous voulez via la méthode AddRange.
implémentez le ienumerable interface