Use enum item name like an attribute parameter - c#

I just want don't use "Managers" for each attribute and use some enum for that.
But it seems it is impossible or I am wrong?
So I try to replace
[RequiresRole("Managers")]
with
[RequiresRole(HardCodedRoles.Managers.ToString())]
...
public enum HardCodedRoles
{
Administrators,
Managers
}

How about a class instead of an enum, making the class static to avoid somebody new:ing it ?
public static class HardCodedRoles
{
public const string Managers = "Managers";
public const string Administrators = "Administrators";
}
[RequiresRole(HardCodedRoles.Managers)]

You could also use the nameof keyword, i.e.:
[RequiresRole(nameof(HardCodedRoles.Managers))]

The reason you see the error is because ToString() is a method and thus the value cannot be calculated at compile time.
If you can use [RequiresRole(HardCodedRoles.Managers)] instead, you can perform the ToString elsewhere in your code, and this could give you the functionality you need. This will require that you change the parameter of your attribute from string to HardCodedRoles.
(I would imagine that using a const won't work, because the type of the parameter will still be string, so the input won't be restricted.)

Related

How to use final class as type in interface (php)

I have a stupid question. I want to learn PHP after 2-3 years of C#.
And like in C#
public enum SimpleEnum{
One,
Two,
Three
}
public interface ISimple
{
int Id;
SimpleEnum SimpleType;
}
What I did in PHP:
final class SimpleEnum {
const ONE = 1;
const TWO = 2;
const THREE = 3;
}
interface ISimple {
public $value1;
SimpleEnum $myEnum;
}
But the error occurred from SimpleEnum in ISimple.
Maybe is not possible but I want to ask you how to use SimpleEnum as type in interface ?
Thank you
Not possible but if you need $myEnum to specifically be SimpleEnum, then just require it in the contract (interface) so any exhibiting classes will HAVE TO follow suit. You can do this by type-hinting
interface ISimple {
public function setMyEnum(SimpleEnum $myEnum);
}
Fatal error: Interfaces may not include member variables... So that, you can't have properties in Interfaces, only methods declarations, instead, you can use abstract class and extend it from it.
Also, in PHP, there is no strict type control. So if you want to declare property, just use public $enum = null and in __construct() init it $this->enum = ...;.
One more thing. If you want to be sure that SimpleEnum is exactly what is stored in $enum property, declare setter for this property setSimpleEnum(SimpleEnum $enum) { ... } where you store passed value to class property. Use it everywhere, where you want to change $enum, so that if you pass anything of class which is not extended from SimpleEnum - you would have a Fatal. Pseudo-Strict type control.
As documented under Type Juggling:
PHP does not require (or support) explicit type definition in variable declaration; a variable's type is determined by the context in which the variable is used.

Constructor with variable parameters on class derived from Attribute does not work

I want to store additional information in my Enum values and therefore came up with Attributes. Since I want a single property to carry 1..n strings I tried to make the attribute constructor accept a variable parameter. Like this:
[AttributeUsage(AttributeTargets.Enum, AllowMultiple = false, Inherited = false)]
public class FileTypeAttribute : Attribute
{
public readonly string[] Extensions;
FileTypeAttribute(params string[] extensions)
{
this.Extensions = extensions;
}
}
My problem is that when I am now trying to make use of my property my compiler complains and leaves with the following error message which I really do not understand:
public enum EFileType
{
[FileTypeAttribute("txt")]
TEXTFILE,
[FileTypeAttribute("jpg", "png")]
PICTURE
}
Gives me:
'FileTypeAttribute' does not contain a constructor that takes '1' arguments and
'FileTypeAttribute' does not contain a constructor that takes '2' arguments
Could anyone tell me please why this happens?
As far as I remember there is not really a possibility to make enums a little more "java'ish". But if I am missing any alternative I would be glad to hear about it.
The constructor is implicitly private - explicitly mark it public:
public FileTypeAttribute(params string[] extensions)
{
this.Extensions = extensions;
}

How to refactor when reflection is used to get methods by name?

Suppose I get a MethodInfo in the following way:
Assembly assembly = Assembly.Load(assemblyName);
Type type = assembly.GetType(nameSpaceName+"."+className);
MethodInfo mi = type.GetMethod("myMethod", bf); // bf are the binding flags.
But later I decide to change the case/name of myMethod.
Is there a way to either:
Refactor so that it changes the name in the string.
Change the reflection call so it gets the method without using the method's name as a string?
The reason for this is so I can test my code which requires the use of reflection, but I'd rather not require that nobody ever change the name of the methods in the code.
If you use Visual Studio to do the refactoring, there is an option to search literal strings and comments for the name and change those too. I highly recommend using the preview when using that option, though, to verify that you're only changing the parts you expect.
Of course, you could use a constant like internal const string methodName = "methodName"; so that you only have the literal string once. You could manually change the one string literal when you refactor the method name. You'd also be able to rename the methodName more easily.
You could use a custom attribute, and decorate your methods with this attribute. Then instead of getting the method by its name, you could get it by the ID defined in the attribute. That way the method name could change as often as it needs to...just a thought.
[AttributeUsage(AttributeTargets.Method)]
public class CustomMethodAttribute : Attribute
{
public string ID { get; set; }
}
Usage:
[CustomMethodAttribute(ID = "UniqueIDHere")]
public void Test()
{
}
Do you have a concrete reference to the type in question?
Even if you don't have it explicitly, you can make the method generic.
public void TestMethod<TargetType>(object o)
{
if (typeof(TargetType).IsAssignableFrom(o.GetType())) {
TargetType strongType = o as TargetType;
strongType.myMethod();
}
}
In fact, you could do this without reflection at all:
public void TestMethod<TargetType>(object o)
{
if (o is TargetType) {
TargetType strongType = o as TargetType;
strongType.myMethod();
}
}
For methods and properties try using expression trees.
You can get reflection-related information from them, saving compile-time checking and enabling automatic refactoring.
I believe you can get assembly-related information and namespace names as well.
Just write several helper functions which can retrieve such information from expression trees.
You can find several helper functions here
They allow write such code:
FirePropertyChanged(() => PropertyName);
which is the same as
FirePropertyChanged("PropertyName");

C# String Resource Values as Enum String Part values?

Using VS2010 and .net V4.0 I would like to achieve the following:
I already have 2 resource files in my project for 2 languages - English and Czech.
I must say Resource Management in .net is excellent, I am suprised even to get code completion when implementing a String for example:
string desc = Strings.ResourceManagerDesc
This gets the string associated with the current culture of the thread.
Now I am trying to create an Enum that can have the String portion of the Enum interpreted from the Strings resources. In the following way (This code DOES NOT WORK):
public enum DownloadStatus
{
1 = Strings.DownloadState_Complete,
2 = Strings.DownloadState_Failed,
3 = Strings.DownloadState_InProgress
}
This is a made up example, but you can see the point here. Since the above code won't work, is there a best practice way to achieve what I want?
This question is old but does not have an accepted answer and I was looking for a good way to do this.
Here's what I did, I built an extension to my Enum so that it returns a value from the Resource Manager :
public enum EventType
{
NewVersion = 1,
Accepted = 2,
Rejected = 3,
BruteForce = 4
}
public static class EventTypeExtension
{
public static string Display(this EventType type)
{
return Strings.ResourceManager.GetString("EventType_" + type);
}
}
I hope this can help someone!
Enums cannot inherit from strings. In code you do not need to be concerned with the language of the code, so your enum can simply contain the relevant states.
Looks like what you need is a utility method to convert the enum value to the relevant string representation - simply make a method for this.
EDIT: when you use an enum to switch on cases, but need further information per enumerated value, I tend to drop the enum and create a host of static references and use those in the check instead. This reference can be a class wrapping an enum value, which could then expose helpful titles or descriptions.
Enums are compiled up as part of the assembly. You're essentially assigning a method to the value of the enum isn't of a constant value - the CLR is not smart enough to work out the value at compile time, it needs to be a constant.
I'd suggest that you create a different enum for each language (forget resources) and use a helper class to return the correct one depending on the langauge-context needed.
IMO, the Enum value should be reflected to the domain and should not specific to UI (language-context).
You may want to do like this
public enum DownloadStatus
{
Complete = 1,
Failed = 2,
InProgress = 3
}
and using some EnumHelper method to get culture specific description in the UI layer
var downloadStatusString = EnumHelper.GetDescription<DownloadStatus>(DownloadStatus.Complete);
and EnumHelper class will read the culture specific string from the Resource file
public static class EnumHelper
{
public static string GetDescription<T>(T value)
where T : struct
{
if (!typeof(T).IsEnum)
{
throw new ArgumentException("value must be Enum.", "value");
}
var name = value.ToString();
string resourceKey = string.Format(CultureInfo.InvariantCulture, "{0}_{1}", typeof(T).FullName, name);
object resource = HttpContext.GetGlobalResourceObject("EnumDescriptions", resourceKey, Thread.CurrentThread.CurrentUICulture);
string description = resource as string ?? name;
return description;
}
}
Note: the resource file name is EnumDescriptions and the key must be this conversion YourNamespace.EnumType_EnumValueInString. (I'm using HttpContext to get the resource value and you might want to change it if you are not using ASP.Net.)
You can get a resource via a string, and since you can convert an enum to a string, this is quite straightforward.
enum Whatever { Ready, Set, Go }
public static string GetEnumerationString(Enum enumeration)
{
string resourceName =
string.Concat(enumeration.GetType().Name, "_", enumeration);
return ResourceManager.GetString(resourceName);
}
Now in this implementation we prefixing all enum resources with the name of the enum. In a project we did it just prevents collisions with other resources and makes them easy to find. You'd have to then ensure adding resources called Whatever_Ready, Whatever_Set and Whatever_Go.
Similarly, if you were to look at the generated code for the static member Strings as you originally wrote you'd probably see:
public static string DownloadStatus_Complete
{
return ResourceManager.GetString("DownloadStatus_Complete", Resource.Culture);
}

C#: static Guid as argument of an attribute

How can I use a static Guid as argument in an attribute?
static class X
{
public static readonly Guid XyId = new Guid("---");
}
[MyAttribute(X.XyId)] // does not work
public class myClass
{
}
It does not work because Guid must be readonly, it can not be const. The string and byte[] representation would also be readonly.
Is there any workaround for this?
It's not possible and will never be possible, because [Attributes] are compiled as metadata and static variables are initialized at runtime, and of course the former cannot access the latter (except via Reflection).
If the standard
public const string MyGuid = "blah";
won't work for you, then AFAIK the only way to achieve what you want, is with Reflection.
Unfortunately there is no a good way to pass Guid to attribute.
Only workaround would be to use another type for that and convert it to Guid.

Categories

Resources