C# 泛型 - 模仿 C++模板专业化

发布于 2024-12-08 12:03:54 字数 1032 浏览 0 评论 0原文

我在 C++ 模板上找到了一个很好的链接:

http://www.cplusplus.com/doc /tutorial/templates/

并需要 C# 中的类似内容。我有一个似乎有效的解决方案,但希望其他人就其与上述链接(特别是专业化部分)的关系提出意见。

这是我提出的概念证明:

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;
    }
}

然后最后调用工厂我这样做:

var piece = new PieceFactory<Pawn, string>("exd6").GetPiece();

piece.CaptureEnPassant();

我看到了不同的解决方案,例如使用扩展方法和其他方式......

只是想看看我的思维方式是否一致好的图案的线条。

非常感谢,

大卫

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

无人接听 2024-12-15 12:03:54

我的观点是,你的草图比必要的更加复杂和混乱。为什么基类有一个“值”,在每个派生类中都有不同的含义和不同的类型?为什么有一个工厂采用的类型参数必须是特定类型参数,如果不是,则程序在运行时崩溃?摆脱所有那些脆弱的、令人困惑的、脆弱的东西。如果 pawn 需要一个字符串,那么在 Pawn 上创建一个接受字符串的公共构造函数,故事结束。这里根本不需要工厂模式。

不要太迷恋这个工具,以至于用它构建实际上没有任何意义的东西。泛型类型非常适合集合类之类的东西。他们不太适合国际象棋领域。

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.

三寸金莲 2024-12-15 12:03:54

仅供参考,为了好玩,我尝试将自己的模板编程国际象棋引擎转换为 C#,结果发现它的速度大约慢了 20 倍。全面 [原文如此]。

这包括解析游戏文件格式之类的内容。位置查找和移动生成在 C++ 版本中有很多机械同情,应用所有技巧并不能弥补:

  • 编译时优化
  • 非共享泛型(单声道特定 - 参见此处,例如
  • 不安全代码(固定数组、原始指针)、
  • 未经检查的块(如数组边界/算术溢出
  • 值)类型化数组和引用传递
  • 短的、内联的函数
  • 垃圾预防(预分配“领域”中的自定义分配(只是预分配的大型结构数组)

也就是说,使用泛型集合的性能优势是显着的,特别是对于 List

YMMV,但最后我想说

1. 采用 C# 方式。如果必须优化,请采用 C# 方式

2. 如果所有其他方法均失败,请求助于 P/Invoke
   (如果满足以下条件,C++/CLR 是最佳选择)您的目标是 Windows)

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:

  • compiletime optimization
  • non-shared generics (mono specific - see here, e.g.)
  • unsafe code (pinned arrays, raw pointers),
  • unchecked blocks (as in array bounds/arithmetic overflow
  • value typed arrays and ref passing
  • short, inlinable functions
  • garbage prevention (custom allocation in preallocated 'realms' (just large arrays of structs preallocated)

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)

雨夜星沙 2024-12-15 12:03:54

我只会在你的基类上使用泛型。这会破坏您的代码中的某些内容吗?

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;
    }
}

我还在您的工厂中放置了一些访问关键字(例如 thisbase)和一个 readonly 修饰符。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文