Cannot read Custom Attributes - c#

I have a problem to read a Custom Attributes.
I have read more tutorial for this, but cannot read the value.
NB: I use a console application.
Main Class
namespace IRCBotter
{
public class IrcBot
{
[UserLevel(LevelRequired = 10)]
void HelpCommand(string user)
{
GetAttribute(typeof(IrcBot));
}
public static void GetAttribute(Type t)
{
// Get instance of the attribute.
UserLevel MyAttribute =
(UserLevel)Attribute.GetCustomAttribute(t, typeof(UserLevel));
if (MyAttribute == null)
{
Message.Error("The attribute was not found.");
}
else
{
// Get the Name value.
Message.Error("Valore " + MyAttribute.LevelRequired.ToString());
}
}
}
}
Attribute Class
namespace IRCBotter.Commands
{
[AttributeUsage(AttributeTargets.All ,AllowMultiple=true)]
class UserLevel : Attribute
{
public int LevelRequired { get; set; }
}
}
on debug, Console say me "The attribute was not found".
Have a one simple working example for get correct value from custom attribute?
In the void HelpCommand
need to check if variable user stored is equal in one stored list
and him level is > in LevelRequired.

You haven't declared the attribute on the class, you defined it on the method HelpCommand. You will have to get the MethodInfo for HelpCommand and call GetCustomAttribute on that. Something along these lines.
MethodInfo method = type.GetMethod("HelpCommand");
UserLevel userLevel = method.GetCustomAttribute<UserLevel>();

Related

On Change of Data Type of a Property update all the local variables Method signatures Which use the property

I have a class say Base Which contains a Property say Id
public abstract class Base
{
public abstract int Id { get; }
}
This abstract class has many concrete derived classes. e.g;
public class Concrete: Base
{
public override int Id
{
get { return importChangekeyLogId; }
}
}
Also In my code solution, there are places where this Property Value is stored in a local variable or passed as a parameter to the method. Check below example where local variable id stores property value and SampleChild2 method accepts int which is the value of Property Id.
public int Sample1(Concrete obj)
{
int id = obj.Id;
SmapleChild2(obj.Id);
return id;
}
public void SmapleChild2(int id)
{
}
Requirement: The above property is just an example we have many such kinds of properties and the estimated time if done manually is 38 days. Therefore, I want to write a utility using Roslyn Through which I can change the data type of Properties to long and also I could find all the references of Properties and update the local variable data types and method signatures. So the final code should be like
public abstract class Base
{
public abstract long Id { get; }
}
public class Concrete: Base
{
public override long Id
{
get { return importChangekeyLogId; }
}
}
public long Sample1(Concrete obj)
{
long id = obj.Id;
SmapleChild2(obj.Id);
return id;
}
public void SmapleChild2(long id)
{
}
Code done till now: I am able to change the abstract class property data type to long using code like below
public override SyntaxNode VisitPropertyDeclaration(PropertyDeclarationSyntax node)
{
PredefinedTypeSyntax _longType = SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.LongKeyword)).WithTrailingTrivia(SyntaxFactory.SyntaxTrivia(SyntaxKind.WhitespaceTrivia, " "));
if (node.Type.ToString() == "int")
{
var propertyName = node.Identifier.ValueText;
if (propertyName == "Id")
{
return node.ReplaceNode(node.Type, _longType);
}
}
return node;
}
I am able to find all the references where the property is being used from the below code. But I am not able to find a way to update the local variable's data type and method signatures which deal with the property value.
if (propertyName == "Id")
{
var propertySymbol = (IPropertySymbol)_semanticModel.GetDeclaredSymbol(node);
var references = SymbolFinder.FindReferencesAsync(propertySymbol, this._solution).Result;
}

Accessing ParseFieldName Property from outside

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().

Setting a field of a class's instance with reflection

I have the following issue related to reflection , I have a method which looks like this :
[TestMethod()]
public void steamAccess()
{
testRead = new TestRead();
SteamMap a = new SteamMap();
// Preparing the parameters of the CSV actions
a.writeMessageParams.UIItemEditText = TestContext.DataRow["SearchQuery"].ToString();
//Read and Execute the TestMethod
testRead.Read(a, TestContext);
}
This is a CodedUITest, SteamMap is a class (uiTest map).
WriteMessageParams is a class, actually the real method is WriteMessage but this class allows me to override the string that gets used into my tests by the WriteMessage method, and I plan to make this part of the code more dynamically in the Read method. :
a.writeMessageParams.UIItemEditText = TestContext.DataRow["SearchQuery"].ToString();
My problem happens in testRead.Read context as follows :
When this method is running I have access to all actions from the respective instance ( a in my case ) and if they are supposed to have to use a a.writeMessageParams.UIItemEditText context I know it, how I get the info isn't the problem, the problem is how to make the previously mentioned code to run dynamically as I have tried :
/* I've done this because I know that each method that is supposed to end up with Params, for example a method called WriteMessage, it's class is called WriteMessageParams*/
public void Read(object obj, TestContext testContext)
{
//simplified code
//trying to access/get to the current instance's WriteMessageParam class
Object testObj = obj.GetType().GetMember(subMethod.Code + "Param");
//null
MessageBox.Show(testObj.GetType().ToString());
// trying to access the UIItemEditText field ( which is declared as public) and modify it accordingly
FieldInfo subMethodField = testObj.GetType().GetField("UIItemEditText");
subMethodField.SetValue(testObj,testContext.DataRow[subMethod.CsvColumn].ToString());
}
I've had a read over this article and tried few things
https://msdn.microsoft.com/en-us/library/6z33zd7h%28v=vs.110%29.aspx
My problem is that I have the object of an instance and I try to access this object's class and modify that class's field .
I'd appreciate any help,
Thanks
Edit 1:
This is how the class I'm trying to access looks like :
public partial class SteamMap
{ //simplified to what classes/methods interest me
public virtual writeMessageParams writeMessageParams
{
get
{
if ((this.mwriteMessageParams == null))
{
this.mwriteMessageParams = new writeMessageParams();
}
return this.mwriteMessageParams;
}
}
public class writeMessageParams
{
#region Fields
/// <summary>
/// Type 'test' in text box
/// </summary>
public string UIItemEditText = "test";
#endregion
}
}
Edit 2 - I've tried by using GetNestedType, still no success....
Object testObj = obj.GetType().GetNestedType("writeMessageParams",BindingFlags.Public);
MessageBox.Show(testObj.GetType().ToString());
If I understand you, you have a class like
public partial class SteamMap
{
private writeMessageParams mwriteMessageParams ;
public virtual writeMessageParams writeMessageParams1
{
get
{
if ((this.mwriteMessageParams == null))
{
this.mwriteMessageParams = new writeMessageParams();
}
return this.mwriteMessageParams;
}
}
public class writeMessageParams
{
public string UIItemEditText = "test";
}
}
(your code doesn't compile because you have writeMessageParams both as the class and the property, so I have changed the property to writeMessageParams1)
And you want to change UIItemEditText, which you can do like
public void UpdateUI(object obj, string newValue)
{
var property = obj.GetType().GetProperty("writeMessageParams1");
var writeMessageParams1 = property.GetValue(obj);
var uiFld = wp.GetType().GetField("UIItemEditText");
uiFld.SetValue(writeMessageParams1, newValue);
}
which can be called like
SteamMap sm = new SteamMap();
Write(sm, "Hello");
The key is to use .GetProperty for the property and .GetField for the field.

Giving parameters a metatag for reflection

I would like to flag a parameter in such a way that I can read the tag via reflection. The reason I want to do this is because I am creating business layer objects that map to a database and I want to flag certain parameters as 'read-only', such as uniqueidentifier fields that are being generated in the database.
I am already iterating through the properties for filling the parameters. This is a snippet of how I'm assigning values...
foreach (var prop in this.GetType().GetProperties())
{
switch (prop.PropertyType.Name)
{
case "Int32":
int tmpInt = -1;
if (!DBNull.Value.Equals(rowFromDatabase[prop.Name]) && int.TryParse(rowFromDatabase[prop.Name].ToString(), out tmpInt))
{
prop.SetValue(sender, tmpInt);
}
break;
case "Boolean":
bool tmpBool = false;
if (!DBNull.Value.Equals(rowFromDatabase[prop.Name]) && bool.TryParse(rowFromDatabase[prop.Name].ToString(), out tmpBool))
{
prop.SetValue(sender, tmpBool);
}
break;
..............
continued...
..............
}
}
I want to be able to access some kind of metadata on a parameter that is accessible via the prop variable shown above where I can specify some kind of extra information. How can I do this?
EDIT: I'd like to set the metadata like this
[CustomTag]
public Guid ID { get; set; }
Extend the class System.Attribute then decorate your properties with your custom attributes.
For example:
public class ReadOnlyAttribute : System.Attribute
{
}
or
public class DbColumnInfoAttribute : System.Attribute
{
public string ColumnName {get; set; }
public bool Required { get; set; }
public DbColumnInfoAttribute( string name, bool req){
ColumnName = name;
Required = req;
}
}
Then use them:
public class YourClass
{
[ReadOnly]
[DbColumnInfo( "User_Name", true)]
public string UserName { get; set; }
}
To read them via Reflection:
var listOfAttrib = prop.GetCustomAttributes(typeof(MyAttribute), true);
I would recommend that ALL of your attribute classes extend a common class so you can get all custom properties without having to know the exact attribute you're looking for otherwise you'll end up having to fire multiple GetCustomAttributes

Extension Method for Custom Attributes

I am working an ASP.net MVC4 website and have model & view model layer. Because of certain reasons I have different names for few properties in Model and ViewModel
Model
public partial class Project
{
public string Desc {get; set;}
}
View Model
public class ProjectViewModel
{
public string Description { get; set; }
}
Now at model layer, I need to use ViewModel name of a property if it is different. I was thinking of creating a custom attribute so that I can have something like this in models:
public partial class Project
{
[ViewModelPropertyName("Description")]
public string Desc {get;set;}
}
and use it at model layer as
string.Format("ViewModel Property Name is {0}", this.Desc.ViewModelPropertyName())
I want this to generic so that if there is no ViewModelPropertyName attribute on a property then it should return the same property name i.e. if Desc property has no attribute then it should return "Desc" only.
Here is what I tried
public class ViewModelPropertyNameAttribute : System.Attribute
{
#region Fields
string viewModelPropertyName;
#endregion
#region Properties
public string GetViewModelPropertyName()
{
return viewModelPropertyName;
}
#endregion
#region Constructor
public ViewModelPropertyNameAttribute(string propertyName)
{
this.viewModelPropertyName = propertyName;
}
#endregion
}
Need help for how to access custom attribute
Current state
public static class ModelExtensionMethods
{
public static string ViewModelPropertyName(this Object obj)
{
// ERROR: Cannot convert from 'object' to 'System.Reflect.Assembly'
System.Attribute[] attrs = System.Attribute.GetCustomAttributes(obj);
foreach (System.Attribute attr in attrs)
{
if (attr is ViewModelPropertyNameAttribute)
{
return ((ViewModelPropertyNameAttribute)attr).GetViewModelPropertyName();
}
}
return string.Empty;
}
}
But this has compile time error:
Unfortunately you can not get the attributes you used to decorate the properties by reflecting on the type of the property itself. I have therefore modified your ViewModelPropertyName(this object) Extension method slightly to take in the name of your desired property.
This method will now take in the name of the property whose attribute you wish to get. If the attribute exists it will return the value passed to its constructor, if it on the other hand, does not exist it will simply return the name of the property you passed in.
public static class ModelExtensionMethods
{
public static string ViewModelPropertyName(this object obj, string name)
{
var attributes = obj.GetType()
.GetCustomAttributes(true)
.OfType<MetadataTypeAttribute>()
.First()
.MetadataClassType
.GetProperty(name)
.GetCustomAttributes(true);
if (attributes.OfType<ViewModelPropertyNameAttribute>().Any())
{
return attributes.OfType<ViewModelPropertyNameAttribute>()
.First()
.GetViewModelPropertyName();
}
else
{
return name;
}
}
}
You can also define the following classes to test this new approach.
[MetadataType(typeof(TestClassMeta))]
class TestClass { }
class TestClassMeta
{
[ViewModelPropertyName("TheName")]
public string FirstName { get; set; }
public string LastName { get; set; }
}
Also, as you can see from the following lines of code, your ViewModelPropertyName(this object, string) Extension method will now be called on the instance of your TestClass, instead of calling it on the property itself.
class Program
{
static void Main()
{
Console.WriteLine(new TestClass().ViewModelPropertyName("FirstName"));
Console.WriteLine(new TestClass().ViewModelPropertyName("LastName"));
Console.Read();
}
}

Categories