Why decimal is not a valid attribute parameter type?
This is a CLR restriction. Only
primitive constants or arrays of
primitives can be used as attribute
parameters. The reason why is that an
attribute must be encoded entirely in
metadata. This is different than a
method body which is coded in IL.
Using MetaData only severely restricts
the scope of values that can be used.
In the current version of the CLR,
metadata values are limited to
primitives, null, types and arrays of
primitives (may have missed a minor
one).
Taken from this answer by JaredPar.
Decimals while a basic type are not a
primitive type and hence cannot be
represented in metadata which prevents
it from being an attribute parameter.
use decimal values as attribute params in c#?
This is a CLR restriction. Only primitive constants or arrays of primitives can be used as attribute parameters. The reason why is that an attribute must be encoded entirely in metadata. This is different than a method body which is coded in IL. Using MetaData only severely restricts the scope of values that can be used. In the current version of the CLR, metadata values are limited to primitives, null, types and arrays of primitives (may have missed a minor one).
Decimals while a basic type are not a primitive type and hence cannot be represented in metadata which prevents it from being an attribute parameter.
Why C# Attribute using params doesn't work with my class but work with strings?
The parameters to an Attribute
constructor must be constants, or Types, or 1-D Arrays of them.
You can't use anything that's merely static readonly. So you're mostly limited to string
, number literals and constants, enums
and Type
. You can't even use Decimal
.
A workaround is for the parameters to your Attribute constructor to be the parameters you can use in your Attribute constructor's code to create its own instance.
NB another common gotcha with Attributes
is that they sometimes turn out to be singletons-per-set-of-parameters. You get little control of Attributes
.
An expression E is an attribute_argument_expression if all of the following statements are true:
- The type of E is an attribute parameter type.
- At compile-time, the value of E can be resolved to one of the following:
- A constant value.
- A System.Type object.
- A one-dimensional array of attribute_argument_expressions.
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/attributes
and
The types of positional and named parameters for an attribute class are limited to the attribute parameter types, which are:
- One of the following types: bool, byte, char, double, float, int, long, sbyte, short, string, uint, ulong, ushort.
- The type object.
- The type System.Type.
- An enum type, provided it has public accessibility and the types in which it is nested (if any) also have public accessibility (Attribute specification).
- Single-dimensional arrays of the above types.
A constructor argument or public field which does not have one of these types, cannot be used as a positional or named parameter in an attribute specification.
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/attributes#attribute-parameter-types
How does one work around the decimal attribute parameter issue?
Went with using a string to handle the rounding issues as Hans mentioned.
If anyone has a better idea, please answer this question and I will mark it.
Why is a NullableT not a valid Custom Attribute Parameter when T is?
Hungry?
is equal to Nullable<Hungry>
, which in terms mean that
[Hunger(NullableHungerLevel = Hungry.CouldEatMySocks)]
is equal to
[Hunger(NullableHungerLevel = new Nullable<Hungry>(Hungry.CouldEatMySocks))]
Since you can only use constant values in named attribute arguments you will have to resort to Shimmy's solution.
Custom Attribute - getting not a valid named attribute argument for an enum
The problem is that the MultiselectComperer
property is nullable. The compiler is complaining because unfortunately you can't make a constant of a nullable type. If you make it non nullable, your class will work just fine.
If you need to represent an third value to the eMultiselectComperer
, enum other than Or
and And
you can create a third enum value as the default value for that enum, like this:
[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
public sealed class FilterAttribute : Attribute
{
public enum eMultiselectComperer
{
Unspecified = 0,
Or,
And
}
public bool IsMultiselect { get; set; }
public eMultiselectComperer MultiselectComperer { get; set; }
}
This way, if the user doesn't specify a value for the MultiselectComperer
property when declaring the attribute, it will default to Unspecified
(or whatever you prefer to call it).
Validate a decimal value
You can use "Range" annotation;
10.50D is min value,50.80D is max value...
[Range(10.50D,50.80D,ErrorMessage ="Error min")]
public decimal Salary { get; set; }
Range attribute specifies the numeric range constraints for the value of a data field. It comes with System.ComponentModel.DataAnnotations (in System.ComponentModel.DataAnnotations.dll)
Having an actual decimal value as parameter for an attribute (example xUnit.net's [InlineData]
You should be able use the String value in the Attribute and set the Parameter type to Decimal, it get's converted automatically by the Test Framework as far as I can tell.
[Theory]
[InlineData("37.60")]
public void MyDecimalTest(Decimal number)
{
Assert.Equal(number, 37.60M);
}
If this doesn't work then you can manually convert it by passing in a String parameter.
[Theory]
[InlineData("37.60")]
public void MyDecimalTest(String number)
{
var d = Convert.ToDecimal(number);
Assert.Equal(d, 37.60M);
}
Passing Func as an attribute parameter to secure MVC routes
Necros' suggestion would work, however you would have to invoke his SecurityGuard
helper in the body of every action method.
If you would still like to go with the declarative attribute-based approach (which has the advantage that you can apply the attribute to the whole Controller) you could write your own AuthorizeAttribute
public class CustomAuthorizeAttribute : AuthorizeAttribute {
public bool EmployeeOnly { get; set; }
private string _company;
public string Company {
get { return _company; }
set { _company = value; }
}
protected override bool AuthorizeCore(HttpContextBase httpContext) {
return base.AuthorizeCore(httpContext) && MyAuthorizationCheck(httpContext);
}
private bool MyAuthorizationCheck(HttpContextBase httpContext) {
IPrincipal user = httpContext.User;
if (EmployeeOnly && !VerifyUserIsEmployee(user)) {
return false;
}
if (!String.IsNullOrEmpty(Company) && !VerifyUserIsInCompany(user)) {
return false;
}
return true;
}
private bool VerifyUserIsInCompany(IPrincipal user) {
// your check here
}
private bool VerifyUserIsEmployee(IPrincipal user) {
// your check here
}
}
Then you would use it as follows
[CustomAuthorize(Company = "Acme")]
public ActionResult AcmeOnlyAction()
{
...
}
[CustomAuthorize(EmployeeOnly = true)]
public ActionResult EmployeeOnlyAction()
{
...
}
Why is decimal not a primitive type?
Although not a direct answer, the documentation for IsPrimitive
lists what the primitive types are:
http://msdn.microsoft.com/en-us/library/system.type.isprimitive.aspx
A similar question was asked here:
http://bytes.com/topic/c-sharp/answers/233001-typeof-decimal-isprimitive-false-bug-feature
Answer quoted from Jon Skeet:
The CLR doesn't need to have any intrinsic knowledge about the decimal
type - it treats it just as another value type which happens to have
overloaded operators. There are no IL instructions to operate directly
on decimals, for instance.
To me, it seems as though decimal
is a type that must exist for a language/runtime wanting to be CLS/CLI-compliant (and is hence termed "primitive" because it is a base type with keyword support), but the actual implementation does not require it to be truly "primitive" (as in the CLR doesn't think it is a primitive data type).
Related Topics
How to Iterate Through a Datatable
Convert Datatable to Ienumerable<T>
Should the Repository Layer Return Data-Transfer-Objects (Dto)
Factory Pattern in C#: How to Ensure an Object Instance Can Only Be Created by a Factory Class
String Interpolation VS String.Format
Dispatcher Invoke(...) VS Begininvoke(...) Confusion
How to Dynamically Change Auto Complete Entries in a C# Combobox or Textbox
How to Store and Retrieve Credentials on Windows Using C#
Only Primitive Types or Enumeration Types Are Supported in This Context
How to Parse Dates with a Suffix "Th", "St" or "Nd" on the Day of the Month
Extract Thumbnail for Any File in Windows
Intersect with a Custom Iequalitycomparer Using Linq
How to Create Byte Array from Httppostedfile
Thread Safe Collections in .Net