|
Three options that spring to mind.
The first is what Navaneeth suggested:
class CellMap<TCell> where TCell : IEquatable<TCell>
{
public void SetMap(TCell[][] newMap, bool redrawAll)
{
/if (newMap[x][y].Equals(bufferMap[x][y])) continue;
}
} The second is similar but a different contraint
class CellMap<TCell> where TCell : class
{
public void SetMap(TCell[][] newMap, bool redrawAll)
{
if (newMap[0][0] == newMap[0][1]) continue;
}
} The last option is to implement a base class that all TCell s must derive from:
class CellMap<TCell> where TCell : CellBase
{
public void SetMap(TCell[][] newMap, bool redrawAll)
{
if (newMap[0][0] == newMap[0][1]) continue;
}
}
class CellBase
{
} I would prefer the last option as I then know how the == operator is implemented.
|
|
|
|
|
I like IEquatable. Its likely that TCell will be a value type.
|
|
|
|
|
I don't understand where generics enter into the problem at all. You want to compare two TCell instances, and TCell is apparently not the generic type (not sure why else you would include the snippet to show that CellMap uses TCell).
Just overriding Equals or the equals operator should suffice.
class TCell
{
int field1;
string field2;
override public bool Equals(object other)
{
if (!(other is TCell)) return false;
return (field1 == other.field1 && field2 == other.field2);
}
static public bool operator ==(TCell x, TCell y)
{
return (x.field1 == y.field1 && x.field2 == y.field2);
}
}
The operator overloading syntax is unfamiliar, but it's just a method after all. The compiler will always look for user-defined operator implementations first and use the default implementations only if no user-defined operators exist. So here, since TCell is a class (a reference type), the compiler will use the user-defined == implementation only where an expression compares two objects of declared type TCell, and otherwise use a reference comparison.
(Of course, another possibility is to make TCell a value type, since the default == will then perform a value comparison rather than a reference comparison. But this alone would be no reason to choose to make TCell a value type!)
|
|
|
|
|
dojohansen wrote: I don't understand where generics enter into the problem at all. You want to compare two TCell instances, and TCell is apparently not the generic type
TCell is a generic type in the example shown by OP.
dojohansen wrote: Just overriding Equals or the equals operator should suffice.
You may need to override GetHashCode() as well.
Best wishes,
Navaneeth
|
|
|
|
|
N a v a n e e t h wrote: TCell is a generic type in the example shown by OP.
OK, re-reading it I see a mention of "CallMap takes a generic type", and I realize that does make a difference in this case.
N a v a n e e t h wrote: ou may need to override GetHashCode() as well.
Not in order to get the comparison he wants, but yes, it is probably not a good idea to consider objects equal based on value comparison yet still create hash codes based on the reference!
A solution then would be something like
class TCell<T>
{
int n;
string s;
public TCell(int n, string s)
{
this.n = n;
this.s = s;
}
public bool Equals<T2>(TCell<T2> obj)
{
return (obj != null && obj.n == this.n && obj.s == this.s);
}
public override int GetHashCode()
{
return s.GetHashCode();
}
}
HTH
|
|
|
|
|
Oops again tho!
Since there is no appropriate Equals method for us to override, we are in fact only overloading it. Hence there's no sense in overriding GetHashCode() after all, or at least if we do so we should still override Equals(object).
|
|
|
|
|
To add an instance of a class to a collection I might have:
ArrayList myAL = new ArrayList();
MyClass MyObject;
myAL.Add( MyObject );
myAl[0] = new MyClass();
The question is if I use myAL.RomveAt(0) how do I delete the object created with new - remembering that I want to keep the array list.
Thanks.
|
|
|
|
|
Maybe I'm missing something, but the ArrayList is still valid, the object is just removed from it.
The object at index 0 will be picked up by the garbage collector;
only two letters away from being an asset
|
|
|
|
|
The problem is that the entry in the ArrayList is a pointer to the object and I will be dealing with an awful lot of entries using a lot of memory (I estimate the project will take up to 200MB in operation) so I'm being cautious.
|
|
|
|
|
As Mark said, plus some comments:
1.
if MyClass has a public Dispose() method (e.g. when it is a Form, a Font, a Pen, ...), you should call it on the object you no longer need, like so:
MyClass toBeDisposed=myAL[0];
myAL[0]=new MyClass();
toBeDisposed.Dispose();
2.
why do you still use ArrayList? it is better to use a generic List (available since .NET 2.0), as that:
- provides type safety (it only accepts what you declare it should accept);
- is faster, it doesn't need casting when using its elements.
Luc Pattyn
I only read code that is properly indented, and rendered in a non-proportional font; hint: use PRE tags in forum messages
Local announcement (Antwerp region): Lange Wapper? Neen!
|
|
|
|
|
Luc,
it is a pure class there is no Dispose unfortunately.
I used ArrayList as an example, List is a good idea.
This is for analysing broadcast video streams so I am being careful about overheads so would deriving the classes I use from IDisposable lead to significant overheads?
|
|
|
|
|
Trollslayer wrote: would deriving the classes I use from IDisposable lead to significant overheads?
No, an interface only requires you to implement predefined members (such as the Dispose method). You could also set a reference to null and, if needed, force the GC to do its duty with a simple method call. System.GC is a static class that provide a handful of easy to use methods. You have to be conservative about forcing the GC to run so only use it when it is "profitable".
|
|
|
|
|
The Dispose pattern doesn't create significant overhead, it is intended to free memory or other resources in a deterministic way and earlier than the garbage collector would, so using it typically results in better program behavior.
There is a dual recommendation:
- if a class offers a public Dispose() method, call it when the object is no longer needed; the bigger the object's footprint, the more important this could be;
- as a consequence, if you create a class that is using unmanaged resources (e.g. memory allocated in some DLL), then you should provide a Dispose() method.
FYI: C# has a using statement[^] that may help, as it calls Dispose automatically.
Luc Pattyn
I only read code that is properly indented, and rendered in a non-proportional font; hint: use PRE tags in forum messages
Local announcement (Antwerp region): Lange Wapper? Neen!
|
|
|
|
|
I'm a little confused... you want to keep the reference to the object you created in your array list, but you want to destroy it? If you destroy it, the reference will no longer be valid anyway.
If you mean you want to destroy the object and not keep a reference, so long as myAL[0] is the only reference, then it will be eligible for garbage collection when you call RemoveAt so will be destroyed automatically at some point (which can't be determined).
As Luc mentioned, if MyClass implements IDisposable then you should call Dispose() on myAL[0] before removing. If not, and MyClass is using unmanaged resources, then you should implement it yourself in MyClass .
|
|
|
|
|
No, when I remove the reference I want to destroy the object.
The problem is that there is going to be a large number of objects using a LOT of memory so I am trying to figure out how to manage this.
In some cases there will be fixed array sizes to I can use a crude approach of creating an object for the required position and then reusing it again but this is not always possible.
|
|
|
|
|
Once there are no references then it will be eligible for collection so you should be OK.
I seem to remember vaguely reports of problems with fragmentation of the Large Object Heap (LOH) causing out of memory issues. I may be wrong (something just rang an alarm bell in my head!), but it may be worth checking out.
|
|
|
|
|
Thanks Dave, I'll probably do that. The fragmentation issue is a good point.
|
|
|
|
|
Yep. objects larger than 85KB are allocated in the LOH, which used to risk fragmentation and an unexpected OutOfMemoryException (often while a lot of memory was free). I had some code that could demonstrate that easily in a matter of milliseconds, however it no longer fails consistently, so I suspect they did something to improve the situation. Not sure what, when, how, and how well though.
FYI: as collections are based on arrays, which grow by doubling their size, they pretty soon end up being large objects (a List<T> is NOT a linked list, it really is an array). So an app that uses lots of lists of more than 20K objects is bound to affect the LOH fragmentation state to some extent.
Luc Pattyn
I only read code that is properly indented, and rendered in a non-proportional font; hint: use PRE tags in forum messages
Local announcement (Antwerp region): Lange Wapper? Neen!
|
|
|
|
|
if I use the following:
List<MyClass> list1;
list1 = new List<MyClass>;
list1.Add(new MyClass());
list1[0].num = 3;
list1.RemoveAt(0);
public class MyClass : Object
{
public int num;
public string str;
}
Any suggestions as to how I can force removal of the object or prove that it has been removed?
|
|
|
|
|
It depends...
The way you've written it, yes as the only reference to the MyClass instance was in list1.
It isn't necessarily destroyed immediately, but it will be eventualy.
|
|
|
|
|
List list1;
list1 = new List;
list1.Add(new MyClass());
list1[0].num = 3;
list1[0] = null;
list1.RemoveAt(0);
public class MyClass : Object
{
public int num;
public string str;
}
modified on Saturday, October 17, 2009 7:32 PM
|
|
|
|
|
Nope. calling RemoveAt moves all list entries by one position (a list is built on top of an array), so the old reference gets overwritten right away; setting it to null first does not help, is a waste of time and space.
Luc Pattyn
I only read code that is properly indented, and rendered in a non-proportional font; hint: use PRE tags in forum messages
Local announcement (Antwerp region): Lange Wapper? Neen!
|
|
|
|
|
I just corrected it with a comment. Setting a reference to null can be useful in object level reference types, right?
class Test
{
byte[] bigArray;
public void Alloc()
{
bigArray = new byte[100000000];
}
public void Dealloc()
{
bigArray = null;
}
}
|
|
|
|
|
correct.
Setting a reference to null is useful in two similar situations:
1) as a class member, when the member is no longer needed whereas the object itself is still alive;
example: a class representing a compiler, it first parses the input and needs a keyword list for that, then it generates output code, for which the keywords are no longer useful, so the list could be nulled halfway.
2) as a local variable in a method, when the method basically has two parts, and the second half doesn't need all the data that existed in the first half.
Otherwise setting a reference to null doesn't make much sense (i.e. a class member at the end-of-life of the object, or a local variable near the end of the method).
BTW: the same applies to files and streams; it does not make sense to flush them when the next thing you do is close them.
Luc Pattyn
I only read code that is properly indented, and rendered in a non-proportional font; hint: use PRE tags in forum messages
Local announcement (Antwerp region): Lange Wapper? Neen!
|
|
|
|
|
Trollslayer wrote: list1.RemoveAt(0); // This removes the reference but does it remove the object?
of course it does NOT delete the object, as:
1) RemoveAt() operates on the list, not on the object; how could it, it has no way of knowing whether the object is still required somewhere (e.g. when another reference exists somewhere, maybe in the same or in another list);
2) the GC is typically not invoked by calling a method that removes, deletes, closes, or shrinks something; it may be called by an action that creates a need for memory, most notably the new keyword.
Luc Pattyn
I only read code that is properly indented, and rendered in a non-proportional font; hint: use PRE tags in forum messages
Local announcement (Antwerp region): Lange Wapper? Neen!
|
|
|
|