随着讨论这里,C#不支持通用属性的声明.所以,我不允许做类似的事情:
[Audit<User> (UserAction.Update)]
public ActionResult SomeMethod(int id){ ...
Run Code Online (Sandbox Code Playgroud)
这就像我的属性impl类中的魅力一样,因为我需要从通用存储库中调用一个方法:
User fuuObj = (User) repository.LoadById<T>(_id);
Run Code Online (Sandbox Code Playgroud)
我尝试使用此解决方案但没有成功.我可以通过类似的东西typeOf(User),但我怎么能用LoadById类型或魔术字符串调用?
*T和User都扩展了一个名为Entity的基类.
所以 - 如果没有特殊原因没有通用属性,
我想知道 - 也许它们会被实现?
那些对ASP.NET MVC动作过滤器来说非常棒.
这不是一个非常重要的问题,我只是好奇为什么不允许这样做.该错误消息不是在解释有帮助的,因为很明显,"ATT" 并从属性继承.
public class Generic<Att> where Att : System.Attribute
{
[Att] //Error: 'Att' is not an attribute class
public float number;
}
Run Code Online (Sandbox Code Playgroud) 让我们从一个简单的视图模型开始:
public class MyViewModel
{
public string Value { get; set; }
public IEnumerable<SelectListItem> Values { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
下拉列表可能如下所示:
@Html.DropDownListFor(m => m.Value, Model.Values)
Run Code Online (Sandbox Code Playgroud)
但是,因为下拉列表需要两个值,所以不能使用它:
public class MyViewModel
{
[UIHint("DropDownList")]
public string Value { get; set; }
public IEnumerable<SelectListItem> Values { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
视图包含:
@Html.EditForModel()
Run Code Online (Sandbox Code Playgroud)
因为下拉知道源代码没有固有的方法,直到你从UIHint中驱逐:
public DropDownListAttribute : UIHintAttribute
{
public DropDownListAttribute (string valuesSource)
: base("DropDownList", "MVC")
{
}
}
Run Code Online (Sandbox Code Playgroud)
那么人们可能会喜欢它:
public class MyViewModel
{
[DropDownList("Planets")]
public string PlanetId{ get; set; }
public IEnumerable<SelectListItem> Planets { …Run Code Online (Sandbox Code Playgroud) 我有一个通用的ASP.NET Core WebApi控制器,如:
public abstract class EntityController<TEntity>
{
public IActionResult Get(string id)
{
var entity = ... //load from database by id
if (entity != null)
return new JsonResult(value, this.SerializerSettings()) {StatusCode 200};
return NotFound();
}
}
Run Code Online (Sandbox Code Playgroud)
我想在Get()方法上应用以下属性:
[ProducesResponseType(typeof(TEntity), 200)] //this causes compilation error.
[ProducesResponseType(typeof(Object), 404)]
Run Code Online (Sandbox Code Playgroud)
目前,唯一的解决方法是覆盖派生控制器中的每个方法并在其中添加属性:
public class DerivedController ?EntityController<MyEntity>
{
[ProducesResponseType(typeof(TEntity), (int) HttpStatusCode.OK)]
[ProducesResponseType(typeof(Object), (int) HttpStatusCode.NotFound)]
public IActionResult Get(string id)
{
return base.Get(id);
}
}
Run Code Online (Sandbox Code Playgroud)
我非常不方便我应该覆盖每个控制器中的每个REST方法,只是为了使用TEntity属性中的具体类型.:-(
有没有更好的工作?
我知道它们是编译时,因此它们不能是通用的,必须用常量值初始化.但是:
如果你反映出他们申请的内容,他们为什么不能获得你会得到的信息呢?
为什么他们不能接受lambda表达式,函数或委托?编译器的函数不是常量吗?
如果上面只有一个是真的,属性可能是一个非常强大的声明工具,相反,它们更像是可以通过反射阅读的注释.
这有点像咆哮,但我真的想知道为什么它们看起来像这样的半特征.
这就是我想要做的.它应该是一个API,用于将资源中的值通过给定属性的函数映射到属性应用的属性.请注意,如果Attributes可以知道它们反映的内容,则抽象类不必存在.我发布这个是因为有人想知道我为什么要为属性构造函数赋予函数,也许是因为我想要做的事情已经完成了.
public delegate void PropertyHandler(object parent, PropertyInfo property, object value);
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class FromResourceAttribute : Attribute
{
private static readonly PropertyHandler m_defaultHandler = (parent, property, value) =>
{
property.SetValue(parent, value, null);
};
public PropertyHandler Handler { get; set; }
public FromResourceAttribute(PropertyHandler handler)
{
Handler = handler;
}
public FromResourceAttribute()
{
Handler = m_defaultHandler;
}
}
public abstract class ResourceDependent
{
public ResourceDependent(ResourceManager resources)
{
var resourceDependentProperties =
from property …Run Code Online (Sandbox Code Playgroud) 如此处所示,在您反映获取属性值之前,不会调用属性构造函数.但是,您可能也知道,只能将编译时常量值传递给属性构造函数.为什么是这样?我想很多人多喜欢做这样的事情:
[MyAttribute(new MyClass(foo, bar, baz, jQuery)]
Run Code Online (Sandbox Code Playgroud)
而不是传递一个字符串(导致字符串类型的代码!)与这些值,变成字符串,然后依靠Regex尝试获取值而不是仅使用实际值,而不是使用编译时警告/错误取决于对于可能抛出与该类无关的异常,除了它调用的方法使用了一些键入错误的属性.
这有什么限制?
我有这个 Web Api 控制器操作:
public Plant<TissueProductionLine> GetPlant(string plant, string range)
{
return _repo.GetPlant(plant, range);
}
Run Code Online (Sandbox Code Playgroud)
启动这个我得到这个:
不应键入数据合同名称为“IGMProdLineDashboard.Models”的“IGMProdLineDashboard.Models.TissueProductionLineGroup”。考虑使用 DataContractResolver 或将任何静态未知的类型添加到已知类型列表中 - 例如,通过使用 KnownTypeAttribute 属性或将它们添加到传递给 DataContractSerializer 的已知类型列表中。
好的,没问题,我将Plant用[KnownType]属性装饰我的对象并指定非原始属性:
[KnownType(typeof(ProductionLineGroups<T>))]
public class Plant<T>: IPlant<T> where T : IProductionLine
{
public Plant ()
{
ProductionLineGroups = new ProductionLineGroups<T>();
}
public ProductionLineGroups<T> ProductionLineGroups { get; set; }
Run Code Online (Sandbox Code Playgroud)
现在我得到一个编译时错误:
'IGMProdLineDashboard.Models.ProductionLineGroups':属性参数不能使用类型参数
重读第一条消息,它想知道派生类型: TissueProductionLineGroup
如果我Plant用这个装饰我的对象,一切正常:
[KnownType(typeof(TissueProductionLineGroup))]
Run Code Online (Sandbox Code Playgroud)
显然,这里的含义是我Plant现在需要了解所有不同类型的生产线,这意味着Plant每当添加新组时我都需要更新。
有没有办法解决?
我想用自定义属性编写枚举,例如:
public enum SomeEnum: long
{
[SomeAttribute<MyClass1>]
Sms = 1,
[SomeAttribute<MyClass2>]
Email = 2
}
Run Code Online (Sandbox Code Playgroud)
但属性不支持泛型.嗯,最类似的解决方案是:
public enum SomeEnum: long
{
[SomeAttribute(typeof(MyClass1))]
Sms = 1,
[SomeAttribute(typeof(MyClass2))]
Email = 2
}
Run Code Online (Sandbox Code Playgroud)
这里有问题:我想Class1继承ICustomInterface,所以使用泛型我可以编写约束:
[AttributeUsage(AttributeTargets.All)]
class SomeAttribute<T> : Attribute where T: ICustomInterface
{
}
Run Code Online (Sandbox Code Playgroud)
但属性不支持泛型.
所以最后的问题是:如何检查编译时间(如T约束)该类型是否正在实现某些接口?
我经常想这样做:
public void Foo(Bar arg)
{
throw new ArgumentException("Argument is incompatible with " + name(Foo));
}
Run Code Online (Sandbox Code Playgroud)
因为如果我更改了Foo的名称,IDE也会重构我的错误消息,如果我将方法的名称(或任何其他类型的成员标识符)放在字符串文字中,将不会发生什么.我知道实现"名称"的唯一方法是使用反射,但我认为性能损失超过了可持续性增益,并且它不会涵盖所有类型的标识符.
括号之间的表达式的值可以在编译时计算(如typeof),并通过更改语言规范进行优化以成为一个字符串文字.你认为这是一个有价值的功能吗?
PS:第一个例子看起来问题只与例外有关,但事实并非如此.想想您可能想要引用类型成员标识符的每种情况.你必须通过字符串文字来做,对吗?
另一个例子:
[RuntimeAcessibleDocumentation(Description="The class " + name(Baz) +
" does its job. See method " + name(DoItsJob) + " for more info.")]
public class Baz
{
[RuntimeAcessibleDocumentation(Description="This method will just pretend " +
"doing its job if the argument " + name(DoItsJob.Arguments.justPretend) +
" is true.")]
public void DoItsJob(bool justPretend)
{
if (justPretend)
Logger.log(name(justPretend) + "was true. …Run Code Online (Sandbox Code Playgroud) c# ×10
attributes ×5
generics ×5
asp.net ×2
reflection ×2
.net ×1
asp.net-mvc ×1
automapper ×1