Reputation: 199
I've found a nice link on C++ Tenmplates:
http://www.cplusplus.com/doc/tutorial/templates/
and needed something similar in C#. I have a solution that seems to work but wanted opinions of others in how it relates to the above link, specifically the specialization section.
Here is a proof of concept I came up with:
public abstract class Piece
{
public object Value { get; set; }
}
public class Rook : Piece
{
public void Capture()
{
int i = (int)this.Value;
}
}
public class Pawn : Piece
{
public void CaptureEnPassant()
{
string s = (string)this.Value;
}
}
public class PieceFactory<P, T> where P : Piece, new()
{
P p;
public PieceFactory(T value)
{
p = new P();
p.Value = value;
}
public P GetPiece()
{
return p;
}
}
and then finally to call into the factory I do this:
var piece = new PieceFactory<Pawn, string>("exd6").GetPiece();
piece.CaptureEnPassant();
I've seen different solutions like using extension methods and other ways...
Just wanted to see if my way of thinking is along the lines of good patterns.
THanks so much,
David
Upvotes: 1
Views: 647
Reputation: 393009
FYI I tried converting my own template-programmed chess engine into C# for fun, and found it was slower by roughly a factor of 20 across the board [sic].
That includes stuff like parsing the gamefile format. Position lookup and move generation just had a lot of mechanical sympathy in the C++ version, that applying all the tricks could not make up for:
That said, the performance benefit from using generic collections is significant, esepcially for, say List<T> where T : struct
. Note however, the caveats from the link above (especially for the new
constraint which has rather pathetic performance on MS. NET due to code sharing; it is basically as slow as using reflection to call the constructor, even for value types).
YMMV, but in the end I'd say
1. Go with the C# way. If you must optimize, do it the C# way
2. If all else fails, resort to P/Invoke
(C++/CLR is a sweet spot if you target Windows)
Upvotes: 1
Reputation: 660058
My opinion is that your sketch is far more complex and confusing than necessary. Why does the base class have a "value" that has different meanings and different types in each derived class? Why is there a factory that takes a type parameter that must be of a particular type argument, and if it is not, then the program crashes at runtime? Get rid of all that brittle, confusing, fragile stuff. If a pawn needs a string, then make a public constructor on Pawn that takes a string, end of story. There's no need for the factory pattern at all here.
Don't be so in love with the tool that you build stuff out of it that doesn't actually make any sense. Generic types are great for things like collection classes. They're not a good fit for the chess domain.
Upvotes: 8
Reputation: 13019
I would just use generics on your base class. Does this break something in your code?
void Main()
{
var factory = new PieceFactory<Rook, int>(20);
factory.GetPiece().Dump();
}
abstract class Piece<TValue>
{
public TValue Value { get; set; }
}
class Rook : Piece<int>
{
public int Capture()
{
// Do something...
return base.Value;
}
}
class Pawn : Piece<string>
{
public string EnPassant()
{
// Do something...
return base.Value;
}
}
class PieceFactory<TKey, TValue> where TKey : Piece<TValue>, new()
{
private readonly TKey piece;
public PieceFactory(TValue value)
{
this.piece = new TKey();
this.piece.Value = value;
}
public TKey GetPiece()
{
return this.piece;
}
}
I have also put some access keywords (like this
and base
) and a readonly
modifier in your factory.
Upvotes: 0