Deserialization causes copies of List-Entries - c#

I'd like to create a very general Model-Layer, which can also be passed arround as JSON. One Model should show a LED-Panel of a RaspberryPi2. Since I'd like to model the Class to be as near as possible to the reality, I force a List to always have 8 * 8 Leds. The Class is looking like this:
public class VisualLedPanel
{
private readonly Lazy<List<VisualLed>> _lazyVisualLeds = new Lazy<List<VisualLed>>(CreateVisualLeds);
public VisualLed this[int x, int y]
{
get
{
var result = VisualLeds.FirstOrDefault(f => f.X == x && f.Y == y);
return result;
}
}
public IEnumerable<VisualLed> VisualLeds
{
get
{
return _lazyVisualLeds.Value;
}
set
{
var tt = value;
}
}
private static List<VisualLed> CreateVisualLeds()
{
var result = new List<VisualLed>();
for (var x = 0; x <= 7; x++)
{
for (var y = 0; y <= 7; y++)
{
result.Add(new VisualLed(x, y));
}
}
return result;
}
}
The problem arises with the Serialization: I'm using the NewtonSoft. Json.Net Serializer, and as far as I've seen, it first accesses the Getter, which causes the Logic to create the Leds, and then sets them afterwards.
The only solution I could think of would either be a Custom-Deserializer or some sort of Constructor shennenigans.
It also seems like the Deserializer doesn't use the Set-Property of the VisualLeds-Value, since my Debugger-Stop never was hitted.
Is there an easy possibility arround to have the best of both worlds? I'd like to have the Model as general as possible without the need of Custom-Deserializer.

The easiest way for you to do this without having to write your own custom JsonConverter will be to serialize your collection of VisualLed objects as a proxy array property, marking the original property as ignored:
public class VisualLedPanel
{
private readonly Lazy<List<VisualLed>> _lazyVisualLeds = new Lazy<List<VisualLed>>(CreateVisualLeds);
public VisualLed this[int x, int y]
{
get
{
var result = VisualLeds.FirstOrDefault(f => f.X == x && f.Y == y);
return result;
}
}
[JsonIgnore]
public IEnumerable<VisualLed> VisualLeds
{
get
{
return _lazyVisualLeds.Value;
}
}
[JsonProperty("VisualLeds")]
VisualLed [] SerializableVisualLeds
{
get
{
return VisualLeds.ToArray();
}
set
{
if (value == null || value.Length == 0)
{
if (_lazyVisualLeds.IsValueCreated)
_lazyVisualLeds.Value.Clear();
}
else
{
_lazyVisualLeds.Value.Clear();
_lazyVisualLeds.Value.AddRange(value);
}
}
}
private static List<VisualLed> CreateVisualLeds()
{
var result = new List<VisualLed>();
for (var x = 0; x <= 7; x++)
{
for (var y = 0; y <= 7; y++)
{
result.Add(new VisualLed(x, y));
}
}
return result;
}
}
Prototype fiddle
For a further discussion, see Why are all the collections in my POCO are null when deserializing some valid json with the .NET Newtonsoft.Json component. Using ObjectCreationHandling.Replace would not be appropriate in this case since you want your Lazy<List<VisualLed>> _lazyVisualLeds to be read-only.

Related

containsValues checking Dictionary<type, object> c#

with ECPoint class :
public class ECPoint
{
private BigInteger p, x, y;
public BigInteger P
{
get { return p; }
set { p = value; }
}
public BigInteger X
{
get { return x; }
set { x = value; }
}
public BigInteger Y
{
get { return y; }
set { y = value; }
}
public ECPoint(BigInteger p, BigInteger x, BigInteger y)
{
this.p = p;
this.x = x;
this.y = y;
}
}
I have a dictionary in C#:
Dictionary<BigInteger, ECPoint> hashTable = new Dictionary<BigInteger, ECPoint>();
and an object of ECPoint Class :
ECPoint gamma = new ECPoint(p, Qx, Qy);
p,Qx,Qy are numerical values
And I did this test :
if (hashTable.ContainsValue(gamma))
{
BigInteger j = -1;
foreach (KeyValuePair<BigInteger, ECPoint> s in hashTable)
{
if (s.Value.X==gamma.X && s.Value.Y==gamma.Y)
{
j = s.Key;
return m*j;
}
}
}
The problem is this test has never given a true value, it is always false, so how to check if the dictionary hashTable contain the values of an object?. Someone can help me, thanks in advance, and I apologize for my English.
You can use FirstOrDefault() linq function to check and get value from hashTable so you don't have to iterate with foreach.
Your code will be like this:
var data = hashTable.FirstOrDefault(a => a.Value.X == gamma.X && a.Value.Y == gamma.Y);
if(data != null){
return data.Key * m;
}
You could either implement Equal and GetHashCode or turn ECPoint into a structure so the compare no longer uses a reference comparison.

How should I make members of a collection aware of their "siblings" in relationship to their position

Context:
Recently I have been working on several simple WPF projects to get more familiar with C# and XAML. They have mostly been recreations of old or simple games such as Minesweeper, Centipede, and Pong. I have decided to up the ante by recreating the SEGA Genesis game Fatal Labyrinth but I have hit a road block in the generation of the labyrinth.
The program works by generating a List of <Cell> which is a class I made that will act as the foundation for tracking the position of entities, the player, and the labyrinth itself. My first issue I encountered was the fickleness of 2D lists, so I decided that the easiest way to fix it would be to create my own generic type Grid<T> which consists of its Dimensions, an int for X and Y respectively, and a List of GridItem<T>, GridItem<T> being its own generic class.
GridItem<T> contains its position, given by X and Y coordinates that represent its location in the grid(These are not to be confused with the X and Y dimensions of Grid which represent the actual size of Grid) and the actual item of type T
The Problem
It would be immensely convenient if I could include a HasTop/HasNorth Boolean in GridItem as well as a TopNeighbor/NorthNeighbor (all of which would be of type T naturally) that way from one member of the grid, I can reference its neighbors directly without having to first confirm that it even has a neighbor and then perform a look up to get what it is. The other problem is that when I set one of the items inside of GridItem I once again have to perform a lookup through Linq and then set it. While I can use Linq, and while it would work, it is extremely bulky and hideous to look at and write.
Attempted Solutions
The first solution I tried was to just put a neighbor for every direction in the GridItem but the problem is the GridItems in the actual grid and the GridItems that are stored as neighbors do not update eachother.
The next natural solution flowing from that was to include in their get and set methods something that would appropriately update them all, and the chain would natural ripple out from there. The problem is that can only work one way because the GridItem is not aware of the Grid in which it is a member.
Very well, the next thing I tried was to just include the Grid of which the GridItem was a member inside the GridItem as a property entitled Parent. This unfortunately creates the "I am my own grandpa issue" as well as encountering the same ripple and recursion problems that would occur in the previous attempted solution.
Answer I am looking for
How can I make GridItem aware of the adjacent GridItems such that it can both get and set them without creating recursive updating or "I am my own Grandpa"
Bonus
Also, if anyone can tell me how to make T only acceptable as a nullable type. For instance I want it to allow things like my Cell which can be returned as null but not Int or Bool which can't be null
Edit:
some people asked for the code so here it is:
public class Grid<T> where T : new()
{
#region Constructors
public Grid() { }
public Grid(List<T> input, int RowLength, int ColumnLength)
{
XDimension = RowLength;
YDimension = ColumnLength;
int x = 0;
int y = 0;
input = input.Take(RowLength * ColumnLength).ToList();
foreach (T item in input)
{
Items.Add(new GridItem<T> { Item = item, Position = new Coordinate { X = (UInt32)x, Y = (UInt32)y } });
x += 1;
if (x >= RowLength)
{
y += 1;
x = 0;
}
}
for (int i = 0; i < RowLength * ColumnLength - Items.Count; i++)
{
Items.Add(new GridItem<T> { Item = new T(), Position = new Coordinate { X = (UInt32)x, Y = (UInt32)y }, SystemGenerated = true });
x += 1;
if (x >= RowLength)
{
y += 1;
x = 0;
}
}
}
#endregion
public enum NeigborSelectionEnum { Top, Bottom, Left, Right };
private List<GridItem<T>> items = new List<GridItem<T>>();
private int xDimension;
private int yDimension;
public List<GridItem<T>> Items
{
get
{
return items;
}
set
{
items = value;
}
}
public int XDimension
{
get
{
return xDimension;
}
set
{
xDimension = value;
}
}
public int YDimension
{
get
{
return yDimension;
}
set
{
yDimension = value;
}
}
public T NeighborOf(NeigborSelectionEnum selectedNeighbor, Coordinate position)
{
switch (selectedNeighbor)
{
case NeigborSelectionEnum.Top:
if (position.Y > 0)
{
return Items.FirstOrDefault(n => n.Position.X == position.X && n.Position.Y == position.Y - 1).Item;
}
return default(T);
case NeigborSelectionEnum.Bottom:
if (position.Y + 1 < YDimension)
{
return Items.FirstOrDefault(n => n.Position.X == position.X && n.Position.Y == position.Y + 1).Item;
}
return default(T);
case NeigborSelectionEnum.Left:
if (position.X > 0)
{
return Items.FirstOrDefault(n => n.Position.X == position.X - 1 && n.Position.Y == position.Y).Item;
}
return default(T);
case NeigborSelectionEnum.Right:
if (position.X + 1 < XDimension)
{
return Items.FirstOrDefault(n => n.Position.X == position.X + 1 && n.Position.Y == position.Y).Item;
}
return default(T);
default:
return default(T);
}
}
public T NeighborOf(NeigborSelectionEnum selectedNeighbor, GridItem<T> item)
{
UInt32 x = item.Position.X;
UInt32 y = item.Position.Y;
switch (selectedNeighbor)
{
case NeigborSelectionEnum.Top:
if (y > 0)
{
return Items.FirstOrDefault(n => n.Position.X == x && n.Position.Y == y - 1).Item;
}
return default(T);
case NeigborSelectionEnum.Bottom:
if (y + 1 < YDimension)
{
return Items.FirstOrDefault(n => n.Position.X == x && n.Position.Y == y + 1).Item;
}
return default(T);
case NeigborSelectionEnum.Left:
if (x > 0)
{
return Items.FirstOrDefault(n => n.Position.X == x - 1 && n.Position.Y == y).Item;
}
return default(T);
case NeigborSelectionEnum.Right:
if (x + 1 < XDimension)
{
return Items.FirstOrDefault(n => n.Position.X == x + 1 && n.Position.Y == y).Item;
}
return default(T);
default:
return default(T);
}
}
}
and here is the GridItem
public class GridItem<T> where T : new()
{
private T item;
private Coordinate position;
private bool systemGenerated = false;
public T Item
{
get
{
return item;
}
set
{
item = value;
}
}
public Coordinate Position
{
get
{
return position;
}
set
{
position = value;
}
}
public bool SystemGenerated
{
get
{
return systemGenerated;
}
set
{
systemGenerated = value;
}
}
public Grid<T> Parent
{
get
{
return parent;
}
set
{
parent = value;
}
}
}
and at present the code is messy from trying to work it out in places other than the class so I can't give you that. However a good example I could give you would be:
List<Cell> MazeMakeStack = new List<Cell>().Add(CellGrid.Items[0, new Random().Next(0,CellGrid.Items.Count-1)]);
do
{
List<string> availableCells = new List<string>();
//Checks the Top neighbor of the `CellGrid` who's Item.Id == MazeMakeStack.Last().Id and checks the Boolean IsVistited which is false by default
if (!IsVisited)
{
availableCells.Add("Top")
}
//repeats this for left, bottom, and right adding them to availableCells respectively
if(availableCells.Count=<0)
{
//resolves the borders of the cell and then removes it from the stack such that the next item can be handled
//(My method is randomized depth first search so this is when the tree has no places to go)
}
else
{
//randomly chooses a member of availableCells
//uses a switch that tests the randomly chosen member of availableCells and then based on that grabs the corresponding neighbor, adding it MazeMakerStack
}
}
while(MazeMakeStack,Count()>0)
Because the GridItem<T> class does not know about any other GridItem<T> items that are in the Grid<T>, you could use a delegate to achieve your goal.
Here is an example:
Grid Class:
public class Grid<T>
{
int width;
int height;
public List<GridItem<T>> Cells { get; set; }
public Grid()
{
foreach (GridItem<T> cell in Cells)
{
cell.onGetNeighbor += OnGetNeighbor;
}
}
private GridItem<T> OnGetNeighbor(GridItem<T> self, Direction direction)
{
GridItem<T> neighbor = null;
switch (direction)
{
case Direction.Top:
neighbor = Cells.FirstOrDefault(cell =>
cell.X == self.X && cell.Y == self.Y - 1);
break;
case Direction.Bottom:
neighbor = Cells.FirstOrDefault(cell =>
cell.X == self.X && cell.Y == self.Y + 1);
break;
case Direction.Left:
neighbor = Cells.FirstOrDefault(cell =>
cell.X == self.X - 1 && cell.Y == self.Y);
break;
case Direction.Right:
neighbor = Cells.FirstOrDefault(cell =>
cell.X == self.X + 1 && cell.Y == self.Y);
break;
default:
break;
}
return neighbor;
}
}
GridItem Class:
public class GridItem<T>
{
public int X { get; set; }
public int Y { get; set; }
public Func<GridItem<T>, Direction, GridItem<T>> onGetNeighbor;
public GridItem<T> GetNeighbor(Direction direction)
{
return onGetNeighbor(this, direction);
}
}
Direction Enum:
public enum Direction
{
Top, Bottom, Left, Right
}
You can use this like so:
// Insert your grid/grid item code here ..
Grid<int> grid = new Grid<int>();
GridItem<int> item = grid.Cells[1];
// Get top neighbor
GridItem<int> neighbor = item.GetNeighbor(Direction.Top);
// Check if top neighbor exists
bool topNeighborExists = item.GetNeighbor(Direction.Top) != null;

Compare two arbitrary JToken-s of the same structure

I would like to compare two arbitrary JTokens of the same type and structure (Json.Net from NewtonSoft).
static int CompareTokens(JToken x, JToken y);
// possible output: 0 / 1 / -1
The main goal is to be able use this method to sort two Json strings, so that even if in the beginning they had the same data, but in the different order, in the end these are two exactly same strings. So the sort criterion doesn't really matter, it just matters that this criterion is always the same. And each small element of data should be taken into account.
JToken can be of one of next several types: Array, Boolean, Date, Float, Guid, Integer, Null, Object, Property, String, TimeSpan, Uri. I don't take into account comparing Bytes, Comment, Constructor, None, Undefined, Raw.
It would be great to gain some idea about comparing JArrays and JObjects. That should be some recursive comparison, because JArrays may consist of other JArrays and JObjects and vice versa. Any idea would be appreciated.
But knowing about comparing simpler types would also be very helpful. I wonder rather about knowing how to convert from JToken to actual type (than about knowing how to do it logically).
JValue has IComparable implemented, but I didn't figure out how to convert simple typed JToken to JValue. Knowing about this would also be helpful.
In Linq-to-JSON, JValue represents a primitive value (string, number, boolean, and so on). It implements IComparable<JValue>, so Json.NET takes care of sorting primitive values for you.
Building off of that, you're going to need to recursively descend the two JToken object hierarchies in parallel. When you encounter the first token with a different .Net type, or different properties (if not a JValue), or with a different value (if a JValue), you need to return back the comparison value.
Keep in mind the following:
A comparison method should be reflexive, antisymmetric and transitive.
Container tokens of different .Net type need to be ordered by type in some consistent manner.
the child tokens of JArray and JConstructor are ordered.
the child tokens of JObject are not, so they need to be compared in some stable, symmetric manner. Walking both in order of property name would seem to work.
There is no obvious way to compare JRaw, so don't try, and let an exception get thrown.
The following is a prototype implementation:
public class JTokenComparer : IComparer<JToken>
{
public static JTokenComparer Instance { get { return instance; } }
static JTokenComparer instance;
static JTokenComparer()
{
instance = new JTokenComparer();
}
readonly Dictionary<Type, KeyValuePair<int, IComparer<JToken>>> dict;
JTokenComparer()
{
dict = new Dictionary<Type, KeyValuePair<int, IComparer<JToken>>>
{
// Order chosen semi-arbitrarily. Putting values first seems reasonable though.
{typeof(JValue), new KeyValuePair<int, IComparer<JToken>>(0, new JValueComparer()) },
{typeof(JProperty), new KeyValuePair<int, IComparer<JToken>>(1, new JPropertyComparer()) },
{typeof(JArray), new KeyValuePair<int, IComparer<JToken>>(2, new JArrayComparer()) },
{typeof(JObject), new KeyValuePair<int, IComparer<JToken>>(3, new JObjectComparer()) },
{typeof(JConstructor), new KeyValuePair<int, IComparer<JToken>>(4, new JConstructorComparer()) },
};
}
#region IComparer<JToken> Members
public int Compare(JToken x, JToken y)
{
if (x is JRaw || y is JRaw)
throw new InvalidOperationException("Tokens of type JRaw cannot be sorted");
if (object.ReferenceEquals(x, y))
return 0;
else if (x == null)
return -1;
else if (y == null)
return 1;
var typeData1 = dict[x.GetType()];
var typeData2 = dict[y.GetType()];
int comp;
if ((comp = typeData1.Key.CompareTo(typeData2.Key)) != 0)
return comp;
if (typeData1.Value != typeData2.Value)
throw new InvalidOperationException("inconsistent dictionary values"); // Internal error
return typeData2.Value.Compare(x, y);
}
#endregion
}
abstract class JTokenComparerBase<TJToken> : IComparer<JToken> where TJToken : JToken
{
protected TJToken CheckType(JToken item)
{
if (item != null && item.GetType() != typeof(TJToken))
throw new ArgumentException(string.Format("Actual type {0} of token \"{1}\" does not match expected type {2}", item.GetType(), item, typeof(TJToken)));
return (TJToken)item;
}
protected bool TryBaseCompare(TJToken x, TJToken y, out int comparison)
{
CheckType(x);
CheckType(y);
if (object.ReferenceEquals(x, y))
{
comparison = 0;
return true;
}
else if (x == null)
{
comparison = -1;
return true;
}
else if (y == null)
{
comparison = 1;
return true;
}
comparison = 0;
return false;
}
protected abstract int CompareDerived(TJToken x, TJToken y);
protected int TokenCompare(JToken x, JToken y)
{
var tx = CheckType(x);
var ty = CheckType(y);
int comp;
if (TryBaseCompare(tx, ty, out comp))
return comp;
return CompareDerived(tx, ty);
}
#region IComparer<JToken> Members
int IComparer<JToken>.Compare(JToken x, JToken y)
{
return TokenCompare(x, y);
}
#endregion
}
abstract class JContainerOrderedComparerBase<TJToken> : JTokenComparerBase<TJToken> where TJToken : JContainer
{
protected int CompareItemsInOrder(TJToken x, TJToken y)
{
int comp;
// Dictionary order: sort on items before number of items.
for (int i = 0, n = Math.Min(x.Count, y.Count); i < n; i++)
if ((comp = JTokenComparer.Instance.Compare(x[i], y[i])) != 0)
return comp;
if ((comp = x.Count.CompareTo(y.Count)) != 0)
return comp;
return 0;
}
}
class JPropertyComparer : JTokenComparerBase<JProperty>
{
protected override int CompareDerived(JProperty x, JProperty y)
{
int comp;
if ((comp = x.Name.CompareTo(y.Name)) != 0)
return comp;
return JTokenComparer.Instance.Compare(x.Value, y.Value);
}
}
class JObjectComparer : JTokenComparerBase<JObject>
{
protected override int CompareDerived(JObject x, JObject y)
{
int comp;
// Dictionary order: sort on items before number of items.
// Order both property sequences to preserve reflexivity.
foreach (var propertyComp in x.Properties().OrderBy(p => p.Name).Zip(y.Properties().OrderBy(p => p.Name), (xp, yp) => JTokenComparer.Instance.Compare(xp, yp)))
if (propertyComp != 0)
return propertyComp;
if ((comp = x.Count.CompareTo(y.Count)) != 0)
return comp;
return 0;
}
}
class JArrayComparer : JContainerOrderedComparerBase<JArray>
{
protected override int CompareDerived(JArray x, JArray y)
{
int comp;
if ((comp = CompareItemsInOrder(x, y)) != 0)
return comp;
return 0;
}
}
class JConstructorComparer : JContainerOrderedComparerBase<JConstructor>
{
protected override int CompareDerived(JConstructor x, JConstructor y)
{
int comp;
if ((comp = x.Name.CompareTo(y.Name)) != 0)
return comp;
if ((comp = CompareItemsInOrder(x, y)) != 0)
return comp;
return 0;
}
}
class JValueComparer : JTokenComparerBase<JValue>
{
protected override int CompareDerived(JValue x, JValue y)
{
return Comparer<JToken>.Default.Compare(x, y); // JValue implements IComparable<JValue>
}
}
Lightly tested prototype fiddle.
This could, actually, be done with less code. Not as nice, because using string comparison instead of JValue comparison.
Following is not an exact answer to my own question, but the goal is achieved.
public static JToken Normalize(this JToken token)
{
var result = token;
switch (token.Type)
{
case JTokenType.Object:
var jObject = (JObject)token;
if (jObject != null && jObject.HasValues)
{
var newObject = new JObject();
foreach (var property in jObject.Properties().OrderBy(x => x.Name).ToList())
{
var value = property.Value as JToken;
if (value != null)
{
value = Normalize(value);
}
newObject.Add(property.Name, value);
}
return newObject;
}
break;
case JTokenType.Array:
var jArray = (JArray)token;
if (jArray != null && jArray.Count > 0)
{
var normalizedArrayItems = jArray
.Select(x => Normalize(x))
.OrderBy(x => x.ToString(), StringComparer.Ordinal);
result = new JArray(normalizedArrayItems);
}
break;
default:
break;
}
return result;
}

How to create dynamic incrementing variable using “for” loop in C#

How to create dynamic incrementing variable using "for" loop in C#? like this:
track_1, track_2, track_3, track_4. so on.
You can't create dynamically-named variables. All you can do - it to create some collection or array, and operate with it.
I think the best class for you is generic List<>:
List<String> listWithDynamic = new List<String>();
for (int i = 1; i < limit; i +=1)
{
listWithDynamic.Add(string.Format("track_{0}", i));
...
}
Assuming you want strings:
for (int i = 1; i < limit; i +=1)
{
string track = string.Format("track_{0}", i);
...
}
But when you already have variables called track_1, track_2, track_3, track_4 you will need an array or List:
var tracks = new TrackType[] { track_1, track_2, track_3, track_4 } ;
for (int i = 0; i < tracks.length; i++)
{
var track = tracks[i]; // tracks[0] == track_1
...
}
Obvious Solution
for (var i = 0; i < 10; i++)
{
var track = string.Format("track_{0}", i);
}
Linq-Based Solution
foreach (var track in Enumerable.Range(0, 100).Select(x => string.Format("track_{0}", x)))
{
}
Operator-Based Solution This is somewhat hacky, but fun none-the-less.
for (var i = new Frob(0, "track_{0}"); i < 100; i++)
{
Console.WriteLine(i.ValueDescription);
}
struct Frob
{
public int Value { get; private set; }
public string ValueDescription { get; private set; }
private string _format;
public Frob(int value, string format)
: this()
{
Value = value;
ValueDescription = string.Format(format, value);
_format = format;
}
public static Frob operator ++(Frob value)
{
return new Frob(value.Value + 1, value._format);
}
public static Frob operator --(Frob value)
{
return new Frob(value.Value - 1, value._format);
}
public static implicit operator int(Frob value)
{
return value.Value;
}
public static implicit operator string(Frob value)
{
return value.ValueDescription;
}
public override bool Equals(object obj)
{
if (obj is Frob)
{
return ((Frob)obj).Value == Value;
}
else if (obj is string)
{
return ((string)obj) == ValueDescription;
}
else if (obj is int)
{
return ((int)obj) == Value;
}
else
{
return base.Equals(obj);
}
}
public override int GetHashCode()
{
return Value;
}
public override string ToString()
{
return ValueDescription;
}
}
don't know if I get your question, but I will try:
for(var i = 1; i < yourExclusiveUpperbound; i++)
{
var track = String.Format("$track_{0}", i);
// use track
}
or with some LINQ-Magic:
foreach(var track in Enumerate.Range(1, count)
.Select(i => String.Format("$track_{0}", i)))
{
// use track
}
Do as follow:
for (int i = 0; i < lenght; i ++)
{
any work do in loop
}
No, we can't create dynamically named variables in a loop. But, there are other elegant ways to address the problem instead of creating dynamically named variables.
One could be, create an array or list before the loop and store values in array / list items in the loop. You can access the array / list later anywhere in your code. If you know which variable you want to use (track_1, track_2, ...), you can simply access it from the array / list (tracks[1], tracks[2], ...).
List<String> tracks = new List<String>();
for (int i = 1; i < limit; i++)
{
Track track = new Track();
tracks.Add(track);
...
}

C# Extend array type to overload operators

I'd like to create my own class extending array of ints. Is that possible? What I need is array of ints that can be added by "+" operator to another array (each element added to each), and compared by "==", so it could (hopefully) be used as a key in dictionary.
The thing is I don't want to implement whole IList interface to my new class, but only add those two operators to existing array class.
I'm trying to do something like this:
class MyArray : Array<int>
But it's not working that way obviously ;).
Sorry if I'm unclear but I'm searching solution for hours now...
UPDATE:
I tried something like this:
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;
}
}
Then use it like this:
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!");
And no effect. I'm not good with interfaces and overriding methods unfortunately :(. As for reason I'm trying to do it. I have some equations like:
x1 + x2 = 0.45
x1 + x4 = 0.2
x2 + x4 = 0.11
There are a lot more of them, and I need to for example add first equation to second and search all others to find out if there is any that matches the combination of x'es resulting in that adding.
Maybe I'm going in totally wrong direction?
For a single type, it is pretty easy to encapsulate, as below. Note that as a key you want to make it immutable too. If you want to use generics, it gets harder (ask for more info):
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);
}
}
Its not permitted to extend the array class, see the reference: http://msdn.microsoft.com/en-us/library/system.array.aspx
You could either implement IList (which has the basic methods), or encapsulate an Array in your class and provide conversion operators.
Please let me know if you need more detail.
Can you not just use the List class? This already does what you want via the AddRange method.
implement the ienumerable interface

Categories

Resources