我的应用程序使用了几个"句柄" (所有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#不允许在结构中使用基类型。
这似乎应该有一个简单而优雅的解决方案,但它逃避了我:(
有什么想法吗?
答案 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中可以做到这一点,但是在调用它或发生零填充的情况下的差异导致了足够的混淆,坚持构造函数匹配零填充确实可以节省一些问题。