gpt4 book ai didi

Allow a custom Attribute only on specific type(仅允许在特定类型上使用自定义属性)

转载 作者:bug小助手 更新时间:2023-10-25 17:31:43 26 4
gpt4 key购买 nike



Is there a way to force the compiler to restrict the usage of a custom attribute to be used only on specific property types like int, short, string (all the primitive types)?

similar to the AttributeUsageAttribute's ValidOn-AttributeTargets enumeration.

有没有办法强制编译器限制自定义属性的使用,使其仅用于特定的属性类型,如int、Short、String型(所有基元类型)?类似于AttributeUsageAttribute的ValidOn-AttributeTarget枚举。


更多回答

No, this isn't possible. The most you could do is write a unit test that uses reflection and validates its usage. But nothing in the compiler will do this.

不,这不可能。您最多只能编写一个使用反射并验证其用法的单元测试。但是编译器中的任何东西都不能做到这一点。

also; you can't add attributes to classes outside your control anyway - so you can't add attributes to int or string. Do you mean "only to properties that are int or string" ? if so, the answer is still "no" ;p

此外,无论如何都不能向控件外部的类添加属性--因此不能向int或字符串添加属性。您的意思是“仅限于int或字符串的属性”吗?如果是这样,答案仍然是“不”;p

@MarcGravell ofcourse I ment int, string properties and not changing the int class itself, But I'll edit. thanks for the answer.

@MarcGravell当然会修改int、字符串属性,但不会更改int类本身,但我会进行编辑。谢谢你的回答。

Some good, workable answers have been given on this duplicate which was asked just 15 days later: stackoverflow.com/questions/8574275/…

对于这份仅在15天后提出的问题,已经给出了一些好的、可行的答案:Stackoverflow.com/Questions/8574275/…

优秀答案推荐

No, you can't, basically. You can limit it to struct vs class vs interface, that is about it. Plus: you can't add attributes to types outside your code anyway (except for via TypeDescriptor, which isn't the same).

不,基本上你不能。您可以将其限制为结构VS类VS接口,仅此而已。另外:无论如何都不能向代码之外的类型添加属性(除了通过TypeDescriptor,这是不同的)。



You can run this unit test to check it.

您可以运行此单元测试来检查它。



First, declare validation attribute PropertyType:

首先,声明验证属性PropertyType:



  [AttributeUsage(AttributeTargets.Class)]
// [JetBrains.Annotations.BaseTypeRequired(typeof(Attribute))] uncomment if you use JetBrains.Annotations
public class PropertyTypeAttribute : Attribute
{
public Type[] Types { get; private set; }

public PropertyTypeAttribute(params Type[] types)
{
Types = types;
}
}


Create unit test:

创建单元测试:



 [TestClass]
public class TestPropertyType
{
public static Type GetNullableUnderlying(Type nullableType)
{
return Nullable.GetUnderlyingType(nullableType) ?? nullableType;
}

[TestMethod]
public void Test_PropertyType()
{
var allTypes = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes());
var allPropertyInfos = allTypes.SelectMany(a => a.GetProperties()).ToArray();

foreach (var propertyInfo in allPropertyInfos)
{
var propertyType = GetNullableUnderlying(propertyInfo.PropertyType);
foreach (var attribute in propertyInfo.GetCustomAttributes(true))
{
var attributes = attribute.GetType().GetCustomAttributes(true).OfType<PropertyTypeAttribute>();
foreach (var propertyTypeAttr in attributes)
if (!propertyTypeAttr.Types.Contains(propertyType))
throw new Exception(string.Format(
"Property '{0}.{1}' has invalid type: '{2}'. Allowed types for attribute '{3}': {4}",
propertyInfo.DeclaringType,
propertyInfo.Name,
propertyInfo.PropertyType,
attribute.GetType(),
string.Join(",", propertyTypeAttr.Types.Select(x => "'" + x.ToString() + "'"))));
}
}
}
}


Your attribute, for example allow only decimal property types:

例如,您的属性只允许使用小数属性类型:



 [AttributeUsage(AttributeTargets.Property)]
[PropertyType(typeof(decimal))]
public class PriceAttribute : Attribute
{

}


Example model:

示例型号:



public class TestModel  
{
[Price]
public decimal Price1 { get; set; } // ok

[Price]
public double Price2 { get; set; } // error
}


The code below will return an error if the attribute was placed on a property/field that is not List of string.

下面的代码将返回一个错误,如果属性被放置在一个属性/字段不是字符串列表。



The line if (!(value is List<string> list)) may be a C#6 or 7 feature.

IF(!(Value is list<字符串>list))行可能是C#6或7的特性。



[AttributeUsage(AttributeTargets.Property |
AttributeTargets.Field, AllowMultiple = false)]
public sealed class RequiredStringListAttribute : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext context)
{
if (!(value is List<string> list))
return new ValidationResult($"The required attrribute must be of type List<string>");

bool valid = false;
foreach (var item in list)
{
if (!string.IsNullOrWhiteSpace(item))
valid = true;
}

return valid
? ValidationResult.Success
: new ValidationResult($"This field is required"); ;
}

}


You could write code yourself to enforce correct use of your attribute class, but that's as much as you can do.

您可以自己编写代码来强制正确使用属性类,但这也是您所能做的。



The way I am doing this is following:

我这样做的方式如下:


[AttributeUsage(AttributeTargets.Property)]
public class SomeValidationAttribute : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
if (value is not string stringToValidate)
{
throw new AttributeValueIsNotStringException(validationContext.DisplayName, validationContext.ObjectType.Name);
}

// validationContext.DisplayName is name of property, where validation attribut was used.
// validationContext.ObjectType.Name is name of class, in which the property is placed to instantly identify, where is the error.

//Some validation here.

return ValidationResult.Success;
}
}

And exception look like this:

异常看起来像这样:


public class AttributeValueIsNotStringException : Exception
{
public AttributeValueIsNotStringException(string propertyName, string className) : base(CreateMessage(propertyName, className))
{

}

private static string CreateMessage(string propertyName, string className)
{
return $"Validation attribute cannot be used for property: \"{propertyName}\" in class: \"{className}\" because it's type is not string. Use it only for string properties.";
}
}


For primitive and sealed types, you are sadly out of luck.

对于原始类型和密封类型,不幸的是您运气不佳。


However, you can indeed limit the use (and visibility) of an attribute to a type hierarchy, by declaring the attribute as an inner class, with protected or internal visibility.

但是,通过将属性声明为具有受保护或内部可见性的内部类,确实可以将属性的使用(和可见性)限制为类型层次结构。


There are, of course, various limits and corner cases here, but it is possible, and probably for a wide variety of use cases.

当然,这里有各种限制和特殊情况,但这是可能的,而且可能适用于各种用例。


Internal visibility can allow you to access these fields from other assemblies if you make them visible to these assemblies.

如果您使这些字段对其他部件可见,则内部可见性允许您从这些部件访问这些字段。


Here is an example of simple automatic validation-time property binding attribute. Tested in Unity 2023.1.12f1.

下面是一个简单的自动验证时间属性绑定属性的示例。已在Unity 2023.1.12f1中测试。


using System;
using System.Reflection;
using UnityEngine;

namespace Tiger.Attributes
{
public class AutoBehaviour : MonoBehaviour
{
[AttributeUsage(AttributeTargets.Field)]
protected class AutoAttribute : PropertyAttribute { }

private void OnValidate()
{
var object_fields = GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
foreach (var field_info in object_fields)
{
if (Attribute.GetCustomAttribute(field_info, typeof(AutoAttribute)) is not AutoAttribute) continue;

var value = GetComponent(field_info.FieldType);
field_info.SetValue(this, value);
}
}
}
}

Usage is straightforward, for example, if you attach this script component to a Cube primitive gameobject, it will automatically look up and serialize the appropriate components.

用法很简单,例如,如果将此脚本组件附加到立方体基本体游戏对象,它将自动查找并序列化适当的组件。


using Tiger.Attributes;
using UnityEngine;

namespace Jovian
{
public class TestBehaviour : AutoBehaviour
{
[Auto] public MeshFilter meshFilter;
[Auto] public MeshRenderer meshRenderer;

// Start is called before the first frame update
private void Start()
{

}

// Update is called once per frame
private void Update()
{

}
}
}

更多回答

what is a ValidationAttribute?

什么是ValidationAttribute?

This forces validation. works in conjunction with the ModelState

这会强制进行验证。与ModelState一起工作

hm I don't have such a type (Unity 2019 with .Net 4.6)

我没有这样的类型(Unity 2019 with .Net 4.6)

@derHugo add Assembly location: C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.ComponentModel.DataAnnotations.dll and namespace using System.ComponentModel.DataAnnotations;

@derHugo添加程序集位置:C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.DataModel.DataAnnotations.dll和命名空间使用System. DataModel.DataAnnotations;

side note: an attribute has no access to it's own context, so any check here would have to be in the reflection code that queries for the attribute

附注:属性无权访问其自己的上下文,因此此处的任何检查都必须在查询该属性的反射代码中进行

I wrote a unit test (NUnit) once that used Cecil to verify my "allowable" attribute usages.

我曾经编写过一个单元测试(NUnit),它使用Cecil来验证我的“允许的”属性用法。

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com