I would like to assign a property string to below attribute.
[ExtractKeyAttribute(**"Extraction"**)]
public class Extract
{
....
}
so extraction is my string but I don't want hard code into there. Any suggestions on better way to assign
You can't do this.
Attribute values must be constant expressions. The values are baked into the compiled code. If you don't want to use a constant expression, you can't use an attribute... and you possibly shouldn't. It may mean you're using attributes when you should be using a different approach.
You might want to read Eric Lippert's blog post on properties vs attributes.
Of course, you don't have to use a string literal there. You could have:
[ExtractKey(ExtractionKeys.Extraction)]
...
public static class ExtractionKeys
{
public const string Extraction = "Extraction";
}
... but it's still a compile-time constant.
In your comments you say you have all (string) values in a static class. Is your static class a class with readonly properties? I mean, do the values change? If not, replace some of those properties in your static class with const strings values. U can use these values to set your attribute.
So...
static class MyClass
{
public string MyValue {get;}
}
would become:
static class MyClass
{
public const string MyValue= "MyValue";
}
Now your attribute can be set as follows:
[ExtractKey(MyClass.MyValue)]
If you want to modify the property of your attribute during runtime, then you can do this with this code:
ExtractKeyAttribute myAttribute = typeof(Extract).GetCustomAttributes(typeof(ExtractKeyAttribute), false)[0] as ExtractKeyAttribute;
myAttribute.MyValue = "MyRunTimeValue";
Related
I'm having the following class:
[DataContract]
class ExampleClass
{
//Properties
[DataMember(Name = "method")]
private const string method = "Example Constant";
...
...
The DataContractJsonSerializer don't seem to include the constant "method" in the JSON output.
How can I keep the member constant, and cause the class to serialize it?
Thank you.
For the JSON-output the const is not accessable at all as it´s private. However serializing a const makes no sense at all, as a const is a static member and belongs to the class itself, not to a specific instance. Therefor the serializer can´t set it on an instance as there is nothing to set on that instance.
Having said this you may wrap your constant in a property:
[DataContract]
class ExampleClass
{
private const string method = "Example Constant";
//Properties
[DataMember(Name = "method")]
public string Method { get; set; }
public ExampleClass(this.Method = method; }
}
PS.: I´m not familiar with contract-serializers, but this is what you would do with an Xml-serializer. Maybe with contract-ser you can also have a get-only property thus you won´t need the extra constructor, but I´m not sure about this.
const is a special keyword in .NET. If you specify field as constant, it would not exist in compiled code, but all the references of constant would be replaced with values of constant at compile time. Therefore this constant does not exist in compiled code and so it is not serialized as well.
The easiest way to fix it is to change constant to regular field (or property) and assign the value in constructor:
[DataContract]
class ExampleClass
{
public ExampleClass()
{
method = "Example Constant";
}
[DataMember(Name = "method")]
private string method;
Alternatively, you can use property:
[DataMember(Name = "method")]
private string Method { get; set; }
Constants are like normal variables. The only difference is that they will replace with the value on compile time.
JSON is a format for transporting data, therefore it does not have any reason for doing something special about constants. But if you have special types like classes or even enums where the name make a difference in the meaning, then there will be additional properties in JSON
In Java I would write something like
public interface ICar {
static String RED_CAR = "/res/vehicles/car_red.png";
static String BLUE_CAR = "/res/vehicles/car_blue.png";
static String GREEN_CAR = "/res/vehicles/car_green.png";
}
Because C# doesn't allow using fields in interface, where do I define this constants in C#, when I wish to use them more than once?
You can define a static class to contain your constants (which need to be public as by default fields without modifier are private):
public static class Car
{
public const string RED_CAR = "/res/vehicles/car_red.png";
public const string BLUE_CAR = "/res/vehicles/car_blue.png";
public const string GREEN_CAR = "/res/vehicles/car_green.png";
}
After this you can use constants like Car.RED_CAR.
If all your constants are files it's better to include them in your resources.
In your project properties there's a resource section, vs can create a Resources.resx if you need one.
In there you can add all sorts of files or strings (for translations mostly).
You can then access them through Properties.Resources.RED_CAR
I would not name them like that though. It's from the time when all variables where globals and naming conventions like that where needed to know what was stored in the variable. But when accessing your data like this it's always clear what's going on.
I want to apply this:
private string _name;
public string name
{
get { return _name; }
set { _name = Fix(value); }
}
to all string the members of a class, and don't want to repeat the same code for all the class members.
An obvious solution would be to put that code on a class to handle the problem and declare all string members as: myString instead of string, however that would mean that I would have to access the main class members like this: email.fixed instead of just email.
So I was wondering, is there is some kind of template I can define and then apply easily?
You could create a Code Snippet for Visual Studio to handle building a property this way.
MSDN includes documentation on Creating a Code Snippet, which can include replacement parameters (the name).
You might want to research Aspect Oriented Programming, which allows you to easily do things like this.
http://www.codeproject.com/Articles/337564/Aspect-Oriented-Programming-Using-Csharp-and-PostS
Create a type with an implicit conversion to and from string:
public class FixedString
{
private string str;
public FixedString(string str){this.str = str;}
public static implicit operator FixedString(string str)
{
return new FixedString(Fix(str));
}
public static implicit operator string(FixedString fixed)
{
return fixed.str;
}
}
You can now create a property of this type, but treat it as if it's a string.
Create a regex replace and use Visual Studio's (v2012/2013) find and replace regex functionality.
For example let us say you have a field like this to change into a property
public string Name;
and you want to change it to have a backing field and the setter you desire.
private string _Name;
public string Name
{
get { return _Name; }
set { _Name = Fix(value); }
}
The find /replace regex pattern in Visual Studio to find is this
public\s+string\s([^;]+);
the replace pattern (with appropriate line spacings and tabs) is this
private string _$1;\r\n\r\n\tpublic string $1\r\n\t{\r\n\t\tget\r\n\t\t\t{ return _$1; }\r\n\t\tset\r\n\t\t\t{\r\n\t\t\t\t_$1 = Fix(value);\r\n\t\t\t}\r\n\t\t}
Then step through the finds and do a replace as needed within your class.
I have done similar to add INotifyChange method calls on blank properties created after doing the code snippet <tab><tab>prop action.
Today, I was cleaning up some of my code with FXCop and it complained about a Attribute class I had with this violation.
CA1019: Define accessor for attribute argument.
On this page, http://msdn.microsoft.com/en-us/library/ms182136.aspx there is more information, but I still do not get the reason for this as it seems to me more verbose and less relevant.
It gives two codes samples.
using System;
namespace DesignLibrary
{
// Violates rule: DefineAccessorsForAttributeArguments.
[AttributeUsage(AttributeTargets.All)]
public sealed class BadCustomAttribute :Attribute
{
string data;
// Missing the property that corresponds to
// the someStringData parameter.
public BadCustomAttribute(string someStringData)
{
data = someStringData;
}
}
// Satisfies rule: Attributes should have accessors for all arguments.
[AttributeUsage(AttributeTargets.All)]
public sealed class GoodCustomAttribute :Attribute
{
string data;
public GoodCustomAttribute(string someStringData)
{
data = someStringData;
}
//The constructor parameter and property
//name are the same except for case.
public string SomeStringData
{
get
{
return data;
}
}
}
}
I don't understand why the SomeStringData property is required. Isn't the someStringData a parameter? Why does it need to have its own property if it is already stored in another property?
Actually, mine is a little different as it looks like this.
[AttributeUsage(AttributeTargets.Property)]
public sealed class ExampleAttribute : Attribute
{
public ExampleAttribute(string attributeValue)
{
this.Path = attributeValue;
}
public string Name
{
get;
set;
}
// Add to add this to stop the CA1019 moaning but I find it useless and stupid?
public string AttributeValue
{
get
{
return this.Name;
}
}
}
Rather than a private field, I have used a public autoproperty, I had to add the last part to make the warning stop but I don't see the point and it also adds another public field to this class, which is redundant, and seems less clean.
That said, I assume that this warning is raised for a reason so what good reason I am missing here?
Thanks in advance.
FxCop is complaining because your existing property doesn't match the parameter name.
Therefore, it doesn't realize that the parameter actually is exposed.
You should rename the property or parameter to match (except for case), or suppress the warning.
FxCop rule CA1019 is just enforcing the .Net Framework coding guidelines for Attributes.
Use named arguments (read/write properties) for optional parameters. Provide a read/write property with the same name as each named argument, but change the case to differentiate between them.
Documentation Link: http://msdn.microsoft.com/en-us/library/2ab31zeh(v=vs.71).aspx
The reason behind the FxCop warning is that every piece of data you pass into the attribute's constructor should be made publicly available to access when the attribute instance is being retrieved by Reflection.
Let's say you have this:
[BadCustom("My String Data")]
public class DecoratedClass
{
}
How will you get "My String Data" back from that attribute instance when you read it using:
BadCustomAttribute attr = typeof(DecoratedClass)
.GetCustomAttributes(typeof(BadCustomAttribute), false)
.Single() as BadCustomAttribute;
Now you have the instance of your attribute, but no way to read the string passed into the constructor because you didn't at least declare a read-only property for it.
the idea is that you should write just:
[AttributeUsage(AttributeTargets.Property)]
public sealed class ExampleAttribute : Attribute
{
public ExampleAttribute(string attributeValue)
{
this.AttributeValue = attributeValue;
}
public string AttributeValue
{
get;
set;
}
}
This violation will also be thrown when the parameter name matches the property name, but the data types are different.
I've never really questioned this before until now. I've got an input model with a number of fields, I wanted to present the string names of the properties through the input model so that my Grid can use them:
public class SomeGridRow
{
public string Code { get;set; }
public string Description { get;set; }
public const string Code = "Code";
}
Obviously, this gives the error:
The type 'SomeGridRow' already
contains a definition for 'Code'
Why can the CLR not cope with two properties of the same name which are, in my eyes, separate?
string code = gridRow.Code; // Actual member from instantiated class
string codeField = SomeGridRow.Code; // Static/Const
I'm now just using a child class called Fields within my inputs now, so I can use SomeGridRow.Fields.Code. It's a bit messy, but it works.
Because you can also access static (or, non-instance in this case) properties in the same way (inside the same class), and it would be a bit confusing, for example:
public class SomeGridRow
{
public string Code { get;set; }
public const string Code = "Code";
public void MyMethod() {
var thing = Code; //what would this reference?
}
}
Because both this:
public class SomeGridRow
{
public string Code { get;set; }
public void MyMethod() {
var thing = Code; //what would this reference?
}
}
And this:
public class SomeGridRow
{
public const string Code = "Code";
public void MyMethod() {
var thing = Code; //what would this reference?
}
}
are valid ways to access properties, static or not. It doesn't answer the "why can't I?" question, but more of the why it's not allowed...it would be far too ambiguous IMO.
It probably could, but the designers of C# wanted to avoid ambiguities that can come from such use (abuse?) of language features.
Such code would end up being confusing and ambiguous to users (did I want the instance or the static method call?, Which one is right?).
In addition to the points already made about ambiguity, i would say that the naming needs to be relooked in such a case.
If two variables / fields having the exact same name in the same context i.e class but different values to me sounds more like a naming issue.
If they are exactly same, you dont need 2 fields.
If they are slightly different, you should have more accurate names.
In some other languages with a similar syntax, one can access a static member through an instance. So you could access both string.Empty and "abc".Empty.
C# doesn't allow this (though it does sort of from inside the class or a derived class, in that you can omit the class name for a static member and can omit this for an instance member), primarily to avoid confusion (I find it more handy than confusion tbh, but that's just me, I like switch fall-through too so what do I know).
Having introduced a stricter rule to allow for less ambiguity, it would be counterproductive to allow a new looser rule on the back of it that allowed for more. Think how many "why must I use this with property X but not property Y?" questions SO would have if it was allowed (we'd have to force this with property X to be clear we meant the instance member).