如何将对象传递到属性构造函数中

60

我正在尝试像下面这样将对象传递给Attributes构造函数:

[PropertyValidation(new NullOrEmptyValidatorScheme())]
public string Name { get; private set; }

使用这个属性构造函数:

 public PropertyValidationAttribute(IValidatorScheme validator) {
      this._ValidatorScheme = validator;
    }

代码无法编译。如何像上面那样将对象传递到属性中?

编辑:是的,NullOrEmptyValidatorScheme实现了IValidatorScheme。

错误:错误 CS0182:属性参数类型必须为常量表达式、typeof表达式或属性创建表达式的数组。


编译错误是什么?您确定 NullOrEmptyValidatorScheme 实现了 IValidatorScheme 吗? - Andrew Hare
就属性语法而言,这是有效的代码,因此它一定与您的对象有关。 - Kenan E. K.
3
@kek444 - 不是这样的...我正在回复中添加规范部分... - Marc Gravell
3个回答

73

将值放入属性中仅限于简单类型,例如基本常量(包括字符串)和typeof,您不能使用new或其他更复杂的代码。简而言之; 您无法这样做。不过,您可以指定类型

[PropertyValidation(typeof(NullOrEmptyValidatorScheme)]
PropertyValidation 构造函数需要一个 Type 类型的参数,并在代码中使用 Activator.CreateInstance 创建对象。请注意,最好只在内部保存字符串 (AssemblyQualifiedName)。
从 ECMA 334v4 中可以看到:
§24.1.3 属性参数类型
用于属性类的位置和命名参数的类型被限制为“属性参数类型”,它们包括:
- 以下类型之一:boolbytechardoublefloatintlongshortstring。 - 类型 object。 - 类型 System.Type。 - 枚举类型,前提是它具有公共可访问性,它所嵌套的类型(如果有)也具有公共可访问性。 - 上述类型的单维数组。
§24.2 属性规范
...
如果以下所有语句都为真,则表达式 E 是属性参数表达式:
- E 的类型是属性参数类型 (§24.1.3)。 - 在编译时,E 的值可以解析为以下之一:
- 常量值。 - typeof-expression (§14.5.11),指定非泛型类型、封闭构造类型(§25.5.2)或未绑定泛型类型(§25.5)。 - 属性参数表达式的一维数组。

这是对允许值之一为枚举的第二次引用,然而实现并非易事。你知道有哪些使用枚举的示例实现吗? - QueueHammer
@QueueHammer [DefaultValue(AnyEnum.SomeValue)] 应该就足够了;否则,可以使用类似 [System.Xml.Serialization.XmlElement(Form = System.Xml.Schema.XmlSchemaForm.Qualified)] 的方式。 - Marc Gravell

10

正如之前的回答者所指出的那样,属性参数中使用的类型非常受限制(可以理解,因为它们的值需要直接序列化到程序集元数据 blob 中)。

尽管如此,您可能可以创建一个利用 typeof 的解决方案,因为这些可以使用。

例如:

[PropertyValidation(typeof(NullOrEmptyValidatorScheme))]
public string Name { get; private set; }

这个语法是完全合法的。读取您的属性的代码必须获取验证器类型,创建验证器的新实例(如果适当,它甚至可以维护以验证器类型为键的验证器缓存 - 这是一种相当常见的技术),然后调用它。


谢谢您的回答。我已经将采纳答案给了Marc。但是您使用缓存的建议很有帮助,我已经设想过这样做以避免多次调用Activator.CreateInstance。 - theringostarrs

5

此外...(我认为这是Microsoft的一个Bug)

你不能将默认值设置为“null”,但简单的默认值如“false”、“7”、“"Test"”是可以的。

下面的示例将会给你以下错误信息: 属性参数必须是常量表达式、typeof表达式或属性参数类型的数组创建表达式
文件:...\CSC

public class SampleAttribute : Attribute
{
    private string _test;
    public SampleAttribute(string test = null)
    {
        _test = test;
    }
}

[Sample]
public class Toto
{

}

可能相关:"属性和命名/可选构造函数参数不起作用" https://dev59.com/KWsy5IYBdhLWcg3w-i_h - user276648
对于用户276648,我认为你是正确的,它们是相关的,那里的解决方案似乎更完整。谢谢! - Eric Ouellet
实际上,根据您提供的示例,这可能与编译器错误有关(也就是说,当使用Mono编译时,您编写的内容可能有效)。https://dev59.com/c2sy5IYBdhLWcg3w0RbT - user276648

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