I used a decompiler to extract all the code from a DLL (SharpSVN -- cannot get my hands on the source code) and I want to modify an enum to give it a DisplayName.
public enum SvnStatus
{
Zero,
None,
[DisplayName("Not Versioned")]
NotVersioned,
//other one-word values that don't need a display name
}
But this gives me the following error:
Attribute 'System.ComponentModel.DisplayNameAttribute' is not valid on this declaration type. It is valid on 'Class, Method, Property, Event' declarations only.
Googled around and found a number of threads where people seem to do this no problem with their enums. Am I missing something? I can't Resolve the error in Visual Studio, the option doesn't even show up (but that might be because I just installed Resharper and am not familiar with it yet?)
Edit: Just found DevExpress has a CustomColumnDisplayText event where I can change the value as desired, so I'm going to go with that instead, since the data is only being displayed in a GridControl.
The reason is given in the error you're getting.
The System.ComponentModel.DisplayNameAttribute has been attributed with a System.AttributeUsageAttribute which constricts the usage to only be applied to classes, methods, properties, or events. Enums are excluded. It looks like this:
[AttributeUsageAttribute(AttributeTargets.Class|AttributeTargets.Method|AttributeTargets.Property|AttributeTargets.Event)]
Perhaps you can write your own attribute instead?
Related
[property: Obsolete]
static int X
{
get { return 42; }
}
In the code above, what purpose does the word "property" serve? The code seems to work the same way if I replace [property: Obsolete] with [Obsolete]. And although "property" is coloured blue in Visual Studio, it does not appear in the list of C# keywords:
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/
The Attribute specification defines this as an attribute target.
Certain contexts permit the specification of an attribute on more than
one target. A program can explicitly specify the target by including
an attribute_target_specifier. When an attribute is placed at the
global level, a global_attribute_target_specifier is required. In all
other locations, a reasonable default is applied, but an
attribute_target_specifier can be used to affirm or override the
default in certain ambiguous cases (or to just affirm the default in
non-ambiguous cases).
It also states that in many cases, like the one you mention, it is permitted but not necessary.
In other contexts, inclusion of an attribute_target_specifier is
permitted but unnecessary. For instance, a class declaration may
either include or omit the specifier type.
This is an attribute target specification.
In your code the use of it is not really necessary, since there is just one allowed target for that attribute at that place. The Obsolete attribute can be placed on a type, method or a property, but if placed on a property, only the property target specifier is allowed (and used implicitly).
The most practical use for this is the assembly target specifier, where you can set assembly configuration through attributes:
[assembly: AssemblyProduct("Foo bar")]
You can set the allowed targets on your custom attributes using AttributeUsage.
I have asked How can I get the number of enums as a constant?, and I found out that I cannot get the count of enums during compile time, because C# uses reflection to do so.
I read What is reflection and why is it useful?, so I have a very basic understanding of reflection.
To get the count of enums, I can use Enum.GetNames(typeof(Item.Type)).Length;, and this happens during runtime using reflection.
I don't see any runtime knowledge needed to get the count of enums, because as far as I know, the count of enums cannot be changed during runtime.
Why does C# have to use reflection to get the count of enums? Why can't it do so during compile time?
Just because something can be evaluated at compile time doesn't mean that someone has programmed the compiler to do so. string.Format("{0:N2}", Math.PI) is another example.
The only way at present to get the count of the number of values of an Enum is by using reflection (Enum.GetNames or something similar). So it is not a constant expression, although technically the compiler could just evaluate the expression at compile-time and determine what the result is.
nameof is a perfect example. It is constant at compile-time, but there was no mechanism to extract the result at compile time until someone designed, developed, tested, documented, and shipped the feature. None of those are free, and thus the idea must compete for valuable resources (people, time, money) against other features that may be more valuable.
So if you feel that a compile-time construct like enumcount(Item.Type) is a valuable addition to the language, then you are more than welcome to post a suggestion on Connect and see if it makes it to the top of the feature list.
But, I need this number as a constant number, so that I can use it in Unity's [Range(int, int)] feature.
One non-ideal workaround is to define a constant that matches the current number of enum items, and throw an exception at run-time if the counts do not match:
Define a public constant right next to your enum, commenting it so that developers know to update it:
// Update this value any time the Type enum is updated
public const int TypeCount = 5;
public Enum Type
{
Bar1,
Bar2,
Bar3,
Bar4,
Bar5,
}
use it in your attribute:
[Range(0, Item.TypeCount)]
public void BlahBlahBlah() {}
and check it at the start of your app:
public static Main()
{
if(Enum.GetNames(typeof(Item.Type)).Length != Item.TypeCount)
throw new ApplicationException ("TypeCount and number of Types do not match.\nPlease update TypeCount constant.")
}
I think in simple terms:
Enums is one "type definition", .NET use Reflection when "type descriptor navigation" is needed.
So Enums is a Type and # runtime, if you want to count the defined enums voice you need to user a reflection.
I don't see any runtime knowledge needed to get the count of enums,
because as far as I know, the count of enums cannot be changed during
runtime.
Here is the mistake in your reasoning: Yes, the count of enums cannot be changed during runtime. However, it can be changed between runtime:
A.dll - version 1
public enum Foo { A }
A.dll - version 2
public enum Foo { Bar, Baz }
Replace version 1 of A.dll with version 2. The count of enums has changed (and the names of the values as well).
Why does C# have to use reflection to get the count of enums? Why
can't it do so during compile time?
It could do so. But then you would run into the problem above. The compile-time calculated value could become incorrect.
I have a library project in my solution that I just added, and whenever I need to reference a class/enum I have to use:
using global::MyName.SubName;
(Resharper automatically suggests this)
Why is this? Why can't I just do:
using MyName.SubName;
Which doesn't work. And even when it does this I am getting this error:
Error 400 Member 'MyName.SubName.Enumerations.SomeEnum.SomeEnumName1' cannot be accessed with an instance reference; qualify it with a type name instead
I can only assume your MyName.SubName being hid (same name) by something else.
See the following MS article for more info: How to: Use the Global Namespace Alias
I think it explains the scenario you are running into.
The ability to access a member in the global namespace is useful when
the member might be hidden by another entity of the same name.
...
However, in larger projects, it is a very real possibility that
namespace duplication may occur in one form or another. In these
situations, the global namespace qualifier is your guarantee that you
can specify the root namespace.
I agree with #kelsey that it looks like a namespace conflict. Another way to resolve it is to use namespacing aliasing like;
using MNSub = MyName.SubName
// ...else where in code
MNSub.MyType varName = new MNSub.MyType(); // etc.
This at least gives a more meaningful syntax than global::...
Just to confirm there isn't a way to avoid hard-coded values in c# attributes right?
[SomeAttribute(3+1)]
public void Foo(string s)
or access class members or do anything not precompiled?
I now explore the great example of retry mechanism in postsharp - and would like to see if I can configure the number of retries from outside the system
Attribute constructor arguments and property values are baked into the compiled code. They can't be determined at execution time.
Of course, if you have attribute which is willing to play ball, you could give it (say) a type and the name of a property, and ask it to fetch that property value at execution time. (That's what NUnit does for [TestCaseSource], for example.) But you can't do this with an attribute which doesn't know to do so.
I do not understand the difference between get_Offset and Offset:
MSDN on NamedRange.get_Offset states
This API supports the Visual Studio infrastructure and is not intended
to be used directly from your code. Use the Offset property instead of
this method.
What does that mean exactly? Similar is also said for get_Value method which is widely used directly in code.
Take following examples which would do the same for me.
myRange.get_Offset(1,0).Value = "Foo";
myRange.Offset[1,0].Value = "Foo";
What are their difference?
get_Something
is an internal function that generates by the CLR for property get accessor.
For example if you have a property
public string Name {get;set;}
after compilation you will find a
get_Name and set_Name methods, cause the properties are nothing then simple wrappers over the set-variable/get-variable concept in a single class domain.
Being an internal method, it's not good practise to make use of it, it's better to use a user defined, clear property access.
get_Offset can theoretically be changed or removed without warning. If the documentation says to use another equivalent method you should do just that.
get_Value is only marked that way for Visual Studio 2005 so you can use that freely
The difference is exactly as the documentation says. You should use the Offset property, not the get_Offset method.
The method is just public because they needed it to be accessible in that way for some other class. The method may just go away in any future version if they find a better way to use the class, and it won't even be mentioned as a breaking change as the documentation clearly states that you shouldn't use it.