C#:如何声明多个相似的结构?

时间:2014-05-22 20:28:52

标签: c# struct

我的应用程序使用了几个"句柄" (所有IntPtr' s)变化"类型"。

我想帮助确保将正确的句柄类型传递给我的各种方法...如果我为它们使用了IntPtr那么那里没有提示该方法采用句柄类型A或句柄类型B. / p>

如果L在C ++中,我可以使用typedef:

typedef uint32 HdlA;
typedef uint32 HdlB;

现在我有两种类型,HdlA和HdlB,两者都是通用的U32引擎盖。 在C ++中,我也可以使用宏来声明结构。

此外,出于编组的原因,我需要将它们作为值类型...不能使用类(当然,如果我可以使用可以解决所有问题的类)。

所有句柄的定义基本相同:

public struct HdlA
{
    private IntPtr _h;
    public bool IsValid             get { return (_h != IntPtr.Zero);} }
    //public HdlA()                 { _h = IntPtr.Zero; } // C# disallows arg-less ctor on struct
    public HdlA(IntPtr h)           { _h = h; }
    public void Invalidate()        { _h = IntPtr.Zero; }
    public static implicit operator IntPtr(HdlA hdl)  { return hdl._h; }
}
public struct HdlB
{
    private IntPtr _h;
    public bool IsValid             get { return (_h != IntPtr.Zero);} }
    //public HdlB()                 { _h = IntPtr.Zero; } // C# disallows arg-less ctor on struct
    public HdlB(IntPtr h)           { _h = h; }
    public void Invalidate()        { _h = IntPtr.Zero; }
    public static implicit operator IntPtr(HdlB hdl)  { return hdl._h; }
}
... etc ...

我当然可以做到这一点 - 我可以声明5或6个相同的代码块,其中只有结构名称不同 - 但这不是很优雅。

我考虑使用接口,但是不允许成员字段,所以没有运气。

我喜欢的是拥有一个基础结构然后让HdlA,HdlB等简单地从基础派生出来。但C#不允许在结构中使用基类型。

这似乎应该有一个简单而优雅的解决方案,但它逃避了我:(

有什么想法吗?

3 个答案:

答案 0 :(得分:1)

一种解决方案是仅使用一个包含所有公共字段的结构,并添加一个字段(int或Enum),以显示要使用的结构的类型。当然,如果您能够使用类,那么您将使用继承,但在这种情况下,添加HandleType字段可以解决问题。

然后,您可以检查每个方法中的该字段,以查看是否已传递正确的结构。

答案 1 :(得分:1)

你没有在你的问题中提供大量的背景,所以我在这里黑暗地刺伤。

毕竟,可能可以在您的情况下使用类。声明抽象基类,从中派生HndlA和HndlB,并在基类上提供ToHandle()方法,将类转换为结构。 ToHandle()的值将是您编组的对象。

再次,只是在黑暗中疯狂地刺伤。

答案 2 :(得分:0)

  

在C ++中,我也可以使用宏来声明结构。

在C#中,您可以使用T4 template

或严格来说,它不是C#本身,虽然它可以使用C#作为脚本语言和输出,并且它可以构成C#中几乎所有构建工具的构建(VisualStudio,MonoDevelop ,SharpDevelop,Nant),而不仅仅是调用编译器本身。

创建一个.tt.t4扩展名的文件,如:

<#@ template language="C#" #>
<#@ output extension=".generated.cs" #>
namespace SomeNamespace
{
<#
foreach(string name in new string[]{"HdlA", "HdlB", /*… and so on… */})
{#>
    public struct <#=name#>
    {
        private IntPtr _h;
        public bool IsValid
        {
            get { return (_h != IntPtr.Zero); }
        }
        public <#=name#>(IntPtr h)
        {
            _h = h;
        }
        public void Invalidate()
        {
            _h = IntPtr.Zero;
        }
        public static implicit operator IntPtr(<#=name#> hdl)
        {
            return hdl._h;
        }
    }
<#}#>
}

它的工作原理与ASP.NET相同,但会生成本地文件。在这里,我们使用它来生成一个.cs文件,然后它将成为编译的一部分,必要时首先重建.cs文件。唉,虽然它是一个生成的文件,如果你没有将它包含在你的源代码控制中,它就会引起问题(必须就这种烦恼提出一个问题)。

Here是我的一个真实例子,它更加真实。这里不是想要使用不同名称的类似类,而是希望使用不同类型的不同方法,但它具有相同的基本原则。

顺便说一下,

  

// C#不允许在struct

上使用arg-less ctor

根据你对它的看法,你也可以说它坚持你必须有一个预定义的无arg零填充构造函数,你无法摆脱或替换(有&#39; s [通常]没有这样的方法,但我们在调用C#中使用new blah()。虽然在.NET中可以做到这一点,但是在调用它或发生零填充的情况下的差异导致了足够的混淆,坚持构造函数匹配零填充确实可以节省一些问题。