如何将GUID作为属性参数?

9

我需要在某些属性类中添加Guid属性,就像这样:

public class SomeAttribute : Attribute {
    private Guid foreignIdentificator;
    public Guid ForeignIdentificator {
        get { return this.foreignIdentificator; }
        set { this.foreignIdentificator = value; }
    }
}

但在属性定义中,我只能使用常量这些原始类型(我理解为什么,这让我感到合理)。解决方法可以是将 "ForeignIdentificator" 定义为字符串,并在运行时创建 GUID:

public class SomeAttribute : Attribute {
    private string foreignIdentificator;
    public string ForeignIdentificator {
        get { return this.foreignIdentificator; }
        set { this.foreignIdentificator = value; }
    }
    public Guid ForeignIdentificatorGuid {
        get { return new Guid( ForeignIdentificator ); }
    }
}

很不幸,我失去了类型安全性的检查。"ForeignIdentificator"属性可以包含任何字符串值,在创建Guid时会在运行时而不是编译时抛出异常。

我知道编译器会检查"System.Runtime.InteropServices.GuidAttribute"的字符串值以进行"Guid兼容性"检查。这个检查正是我需要的,但我不知道这个检查是否是硬编码在编译器中的,还是可以显式地定义(以及如何定义)。

您知道保护属性的"Guid兼容性"检查的方法吗?或者其他方法,如何实现类型安全的Guid定义? 谢谢。


"ForeignIdentificator" 是 GUID 值,应该添加属性所有者的程序集、数据库或其他地方定义。 - TcKs
这听起来像是布什式的说法。 - xr280xr
2个回答

9
我曾经也遇到过你类似的问题,我们只需要求他们将GUID作为字符串传递...默认情况下,VS GUID生成器工具以这种方式提供给我们(* F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4)。实际上,我们做了你所做的。我们在插件架构中使用它,因此我们的客户是使用接口的人。如果您看一下Microsoft进行相同操作时所做的事情,他们也是这样做的。
用这种方式做过一次也没有出现问题。我们从未从现场看到这是一个问题。
您可能需要将该字符串字段命名为GUID,以免混淆您的消费者。添加一些文档,以防他们不知道所需格式。
当我看到这个时,我有同样的反应...但随后我就放弃了,因为似乎没有类型安全的解决方案。

写新的Guid对我来说不是问题(我有一个快捷键),但我担心其他人。但如果没有办法在编译时保证正确的格式(我害怕没有),我必须创建一个实用程序,测试编译后程序集中的所有属性定义。 - TcKs
我理解你的担忧。我们也花了一些时间试图弄清楚它。在微软的实现中,他们也是这样做的,所以我们放弃了。再次强调,我们担心这可能会成为一个问题,但它从未成为过问题。只需确保在你的端口捕获异常即可。 - Brian Genisio
你证实了我的猜想。我不会再寻找其他的解决方案了。 - TcKs

5

属性参数必须是常量。如果我违反规则,我的C#编译器会报错:

属性参数类型必须是常量表达式、typeof表达式或属性参数类型的数组创建表达式

由于在C#中没有GUID字面值,因此您必须使用另一种格式对GUID进行编码,例如字符串。但是,您并不完全陌生:可以使属性具有接受所需格式的构造函数。以下是一个示例,其中包含与 System.Guid 相同的构造函数:

[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
sealed class MyGuidAttribute : Attribute
{
    public Guid Guid { get; private set; }

    //
    // Summary:
    //     Initializes a new instance of the System.Guid class using the specified array
    //     of bytes.
    //
    // Parameters:
    //   b:
    //     A 16 element byte array containing values with which to initialize the GUID.
    //
    // Exceptions:
    //   System.ArgumentNullException:
    //     b is null.
    //
    //   System.ArgumentException:
    //     b is not 16 bytes long.
    public MyGuidAttribute(byte[] b)
    {
        this.Guid = new Guid(b);
    }
    //
    // Summary:
    //     Initializes a new instance of the System.Guid class using the value represented
    //     by the specified string.
    //
    // Parameters:
    //   g:
    //     A System.String that contains a GUID in one of the following formats ('d'
    //     represents a hexadecimal digit whose case is ignored): 32 contiguous digits:
    //     dddddddddddddddddddddddddddddddd -or- Groups of 8, 4, 4, 4, and 12 digits
    //     with hyphens between the groups. The entire GUID can optionally be enclosed
    //     in matching braces or parentheses: dddddddd-dddd-dddd-dddd-dddddddddddd -or-
    //     {dddddddd-dddd-dddd-dddd-dddddddddddd} -or- (dddddddd-dddd-dddd-dddd-dddddddddddd)
    //     -or- Groups of 8, 4, and 4 digits, and a subset of eight groups of 2 digits,
    //     with each group prefixed by "0x" or "0X", and separated by commas. The entire
    //     GUID, as well as the subset, is enclosed in matching braces: {0xdddddddd,
    //     0xdddd, 0xdddd,{0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd}} All braces, commas,
    //     and "0x" prefixes are required. All embedded spaces are ignored. All leading
    //     zeroes in a group are ignored.  The digits shown in a group are the maximum
    //     number of meaningful digits that can appear in that group. You can specify
    //     from 1 to the number of digits shown for a group. The specified digits are
    //     assumed to be the low order digits of the group.
    //
    // Exceptions:
    //   System.ArgumentNullException:
    //     g is null.
    //
    //   System.FormatException:
    //     The format of g is invalid.
    //
    //   System.OverflowException:
    //     The format of g is invalid.
    public MyGuidAttribute(string g)
    {
        this.Guid = new Guid(g);
    }
    //
    // Summary:
    //     Initializes a new instance of the System.Guid class using the specified integers
    //     and byte array.
    //
    // Parameters:
    //   a:
    //     The first 4 bytes of the GUID.
    //
    //   b:
    //     The next 2 bytes of the GUID.
    //
    //   c:
    //     The next 2 bytes of the GUID.
    //
    //   d:
    //     The remaining 8 bytes of the GUID.
    //
    // Exceptions:
    //   System.ArgumentNullException:
    //     d is null.
    //
    //   System.ArgumentException:
    //     d is not 8 bytes long.
    public MyGuidAttribute(int a, short b, short c, byte[] d)
    {
        this.Guid = new Guid(a, b, c, d);
    }
    //
    // Summary:
    //     Initializes a new instance of the System.Guid class using the specified integers
    //     and bytes.
    //
    // Parameters:
    //   a:
    //     The first 4 bytes of the GUID.
    //
    //   b:
    //     The next 2 bytes of the GUID.
    //
    //   c:
    //     The next 2 bytes of the GUID.
    //
    //   d:
    //     The next byte of the GUID.
    //
    //   e:
    //     The next byte of the GUID.
    //
    //   f:
    //     The next byte of the GUID.
    //
    //   g:
    //     The next byte of the GUID.
    //
    //   h:
    //     The next byte of the GUID.
    //
    //   i:
    //     The next byte of the GUID.
    //
    //   j:
    //     The next byte of the GUID.
    //
    //   k:
    //     The next byte of the GUID.
    public MyGuidAttribute(int a, short b, short c, byte d, byte e, byte f, byte g, byte h, byte i, byte j, byte k)
    {
        this.Guid = new Guid(a, b, c, d, e, f, g, h, i, j, k);
    }
    //
    // Summary:
    //     Initializes a new instance of the System.Guid class using the specified unsigned
    //     integers and bytes.
    //
    // Parameters:
    //   a:
    //     The first 4 bytes of the GUID.
    //
    //   b:
    //     The next 2 bytes of the GUID.
    //
    //   c:
    //     The next 2 bytes of the GUID.
    //
    //   d:
    //     The next byte of the GUID.
    //
    //   e:
    //     The next byte of the GUID.
    //
    //   f:
    //     The next byte of the GUID.
    //
    //   g:
    //     The next byte of the GUID.
    //
    //   h:
    //     The next byte of the GUID.
    //
    //   i:
    //     The next byte of the GUID.
    //
    //   j:
    //     The next byte of the GUID.
    //
    //   k:
    //     The next byte of the GUID.
    [CLSCompliant(false)]
    public MyGuidAttribute(uint a, ushort b, ushort c, byte d, byte e, byte f, byte g, byte h, byte i, byte j, byte k)
    {
        this.Guid = new Guid(a, b, c, d, e, f, g, h, i, j, k);
    }
}

你说得对。我也使用字符串将 GUID 传递给属性。 - IlPADlI

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接