In my application I have a custom attribute calles ResourceTargetAttribute which looks like:
[AttributeUsage(AttributeTargets.Property)]
private class ResourceTargetAttribute : Attribute
{
public ResourceTargetAttribute(string resourceKey)
{
ResourceKey = resourceKey;
}
public string ResourceKey { get; private set; }
}
The usage looks like:
[ResourceTarget("FileNotFoundErrorText")
public string FileNotFoundErrorText { get; private set; }
The constructor of the class where the FileNotFoundErrorText-Property is defined resolves this attribute. This just works fine.
Now I was thinking about to extend the attribute to have a parameterless constructor and if this is called the name of the Property the attribute is on will automatically be used for the ResourceKey.
Therefore I've introduced a new constructor which just looks like:
public ResourceTargetAttribute()
{
}
And the usage then should look like:
[ResourceTarget()]
public string FileNotFoundErrorText { get; private set; }
And here I want to have name of the FileNotFoundErrorText-Property automatically be passed to the ResourceTarget-Attribute.
Is there a possibility to do this?
The CallerMemberNameAttribute might help you:
public ResourceTargetAttribute([CallerMemberName] string propertyName = null)
{
ResourceKey = propertyName;
}
Usage:
[ResourceTarget]
public string FileNotFoundErrorText { get; private set; }
If you get the attribute, the
attr.ResourceKey
property should contain FileNotFoundErrorText as value.
Otherwise I just would go the way passing the name as string as attributes are metadata applied to the members of a type, the type itself, method parameters or the assembly so you must have the original member itself to access its meta data.
The easiest way would be to utilize nameof-operator:
[ResourceTarget(nameof(FileNotFoundErrorText)]
public string FileNotFoundErrorText { get; private set; }
Another approach would be to modify the code that actual examines / searches for these marker-attributes. use reflection to get the actual Property-Name on which the attribute was applied.
Maybe if you provide the mentioned "constructor-code" I could further assist.
Related
I have multiple web requests that post JSON object and I have serializable classes with all the fields. For example:
[Serializable]
public class RequestOne()
{
public string date;
public string information;
public string subject;
}
[Serializable]
public class RequestTwo()
{
public int ID;
public string Data;
public string message;
}
And my method takes partially filled request class and I want to fill in any missing fields with default values declared in constant class.
And I want to avoid writing each method with for each request, like :
public static void FillWithDefault(this RequestOne request)
{ if (request.date.Equals(null)) request.date = DEFAULT_DATE;
if (request.information.Equals(null)) request.information = DEFAULT_INFO;
if (request.subject.Equals(null)) request.subject = DEFAULT_SUBJECT;
}
public static void FillWithDefault(this RequestTwo request)
{
//do the same for the fields in RequestTwo
}
I want to know if there is any way to achieve this using generic?
I want to do something similar to this:
public static void FillWithDefault<T>(this T request)
{
if(typeof(T) == typeof(request))
{
//check each member in request and fill with default if it's null
}
.
.
.
}
So that in my main method I can use like this :
RequestOne request = new RequestOne();
request.FillWithDefault();
RequestTwo request2 = new RequestTwo();
request2.FillWithDefault();
Can someone please help with idea on this? Am I overthinking on this? I'm new to generic so please feel free to advise on my code.
Edit
Sorry guys, I did not mention that I will be using this method for test automation. Those request contracts cannot be changed since it's by design. Sorry again for the confusion!
Use constructors. Also make use of properties. Don't gather the default filling code to one place, it's the responsibility of the classes so keep them there.
[Serializable]
public class RequestOne()
{
public string date { get; set; };
public string information { get; set; };
public string subject { get; set; };
public RequestOne()
{
Date = DEFAULT_DATE;
Information = DEFAULT_DATE;
Subject = DEFAULT_SUBJECT;
}
}
[Serializable]
public class RequestTwo()
{
public int ID { get; set; };
public string Data { get; set; };
public string Message { get; set; };
public RequestTwo()
{
Data = DEFAULT_DATA;
message = DEFAULT_MESSAGE;
}
}
Generics are used when the types have common operations/properties defined so you can apply the same routine for each type in one place instead of declaring different methods for each type.
However in this case, you have two different types with different properties, so I would not use generics here. You can achieve it with manual type checking and using reflection to get properties and set them but it's not a good way and definitely wouldn't be a good usage of generics.
Overloading is the way to go.
you can use property
[Serializable]
public class RequestOne()
{
private string _date;
public string date { get { return _date;} set { _date = value ?? DEFAULT_DATE; }};
public string information; // same here
public string subject; //same here
}
I'm trying to create a collection (list<> or IEnumerable<>) of a custom objet "InventorAttribue" that has 2 properties; Name and Value.
The "Value" property can be of various type so I thought of coding this object like this:
public class InventorAttribute<T> {
public InventorAttribute (string name, T value) {
Name = name;
Value = value;
}
public string Name { get; set; }
public T Value { get; set; }
}
Further I plan to use an "AttiributeSet" class to represent the final Autodesk Inventor AttributeSet to be stored in an Inventor's object. Here is the class and where my question stands, because of course, this code does not work as the type 'T' cannot be found (!)
public class AttributeSet
{
public AttributeSet(string category, string name {
Name = name;
Attributes = new List<InventorAttribute<T>>();
}
public string Category { get; set; }
public string Name { get; set; }
public List<InventorAttribute<T>> Attributes { get; set; }
public void AddAttribute(string name, T value){
Attributes.Add(new InventorAttribute<T>(name,value));
}
}
Question:
How can I manage to write this code, and being able to pass the "InventorAttribute.Value" type only at run time through the "AddAttribute" method.
Thanks in advance for greatly appreciated help.
Your AttributeSet class should be also parametrized:
public class AttributeSet<T>
NOTE: you cannot store InventorAttribute<T> parametrized with different T types in Attributes collection. Even if you could do that, how would you consume such collection? You will need to cast Value for each attribute to appropriate type. You will not have any benefits of having generic class here. So create non-generic InventorAttribute which will store values in property of object type.
You're probably imagining some form of inheritance. It doesn't exist here.
An InventorAttribute<string> is not a subclass of InventorAttribute<T>. Nor is it a subclass of InventorAttribute<object> (I mention this since it's usually people's next attempt to define the collection's item type). Each constructed generic type is effectively independent1.
If applicable, you may be able to introduce a new base class:
public abstract class InventorAttribute {
public string Name { get; set; }
public InventorAttribute (string name) {
Name = name;
}
}
public class InventorAttribute<T> : InventorAttribute {
public InventorAttribute (string name, T value) : base(name) {
Value = value;
}
public T Value { get; set; }
}
And you can now declare your collection to be of non-generic type InventorAttribute. But now you cannot access the Values until you cast to the more specific type.
1So far as the type system is concerned. As an implementation detail, the system is able to cleverly JIT only a single version of each method body that is applicable for all reference types. But that doesn't have any visible impact in the type system.
I have a parse subclass like:
[ParseClassName("_User")]
public class RFUser : ParseUser
{
[ParseFieldName("firstname")]
public string Firstname
{
get { return GetProperty<string>(); }
set { SetProperty(value); }
}
}
Is it possible to read the ParseFieldName ("firstname") from other parts of the program?
Something like:
typeof(RFUser).ParseFieldNames.Firstname ?
You are close. The ParseClassName and ParseFieldName attributes appear to be custom attributes. If so, you can access them if you get the name of the property that is set by the attribute's constructor.
Because I do not have (or don't know I have) the DLL that defines the ParseFieldName attribute's class, I created it as follows:
public class ParseFieldName: Attribute
{
public string Name { get; set; }
public ParseFieldName(string name)
{
this.Name = name;
}
}
For reference, my RFUser class is defined as:
[ParseClassName("_User")]
public class RFUser
{
[ParseFieldName("fieldfirstname")]
public string Firstname { get; set; }
}
Elsewhere in the program, I have a class with a using System.Reflection statement and that has a method containing the following code snippet:
RFUser user = new RFUser();
var attribute = (ParseFieldName)user.GetType().GetProperty("Firstname").GetCustomAttribute(typeof(ParseFieldName));
Console.WriteLine(attribute.Name);
The value displayed in the console is fieldfirstname.
You can also access regular attributes if you substitute Attributes for GetCustomAttributes().
Is it possible to access the type of a property from an attribute that has been implemented on to that property?
public class FooAttribute : Attribute
{
public string GetPropertyName()
{
// return ??
}
}
public class Bar
{
[FooAttribute]
public int Baz { get; set; }
}
I would like GetPropertyName() to return "Baz".
Sriram Sakthivel is correct that this is not possible but if you are using .net 4.5 you can create a workaround using the CallerMemberNameAttribute to pass the caller into the constructor of your attribute, store it and then return it from your GetPropertyName method:
public class FooAttribute : Attribute
{
public string PropertyName { get; set; }
public FooAttribute([CallerMemberName] string propertyName = null)
{
PropertyName = propertyName;
}
public string GetPropertyName()
{
return PropertyName;
}
}
This will pass the caller (the property) to the constructor of your attribute.
More details on the CallerMemberNameAttribute are available on MSDN.
What you're asking is not possible. Because Attributes and properties doesn't have "One to One" relationship. You can apply FooAttribute to any number of Properties, In such case which property you need to return from GetPropertyName method?
As I said in comments you can loop through all the types and its properties to see which are all the properties have FooAttribute but obviously that's not what you want.
What i am trying to do, is to translate an application that uses attributes to set text in controls. I was thinking about custom reources manager but attributes has to be hardcoded.
My question is:
Is there any way to change visible text set by an attribute using PostSharp and where are the attributes stored in runtime?
e.g. for code
[DataMember]
[DisplayName("Mission description")]
[Description("Description of this mission")]
public string Description { get; set; }
What do i want to achive is to extract "Mission description" and "Description of this mission" to external file, translate it, and pass new translated values to Description String as an Attribute during execution of program.
What i had to do was to create a class that inherits from System.ComponentModel.DisplayNameAttribute, name it "DisplayNameAttribute" to override parent class, and overwrite parent class constructor, "DisplayName" and "DisplayNameValue" properties.
Next I put my logic into DisplayNameValue getter.
Then create DescriptionAttribute class by analogy.
public class DisplayNameAttribute : System.ComponentModel.DisplayNameAttributes
{
private string name;
public DisplayNameAttribute() { }
public DisplayNameAttribute(String name) { this.name = name; }
public override string DisplayName
{
get
{
return DisplayNameValue;
}
}
public string DisplayNameValue
{
get
{
/* e.g logic for reading from dictionary file */
return myDictionary[name];
}
set
{
name = value;
}
}
}
}
Where "string name" is where i hold my key to Dictionary.