In my following code snippet, I'm not able to understand as to why "customAttribute" value for property "XX" is always null.It works fine for property "X" though.
Any ideas?
Thanks.
System.Reflection.PropertyInfo[] props = myInp.GetProperties();
foreach (var prop in props)
{
if (prop.Name == "XX")
{
var customAttribute = prop.GetCustomAttribute(typeof(CustomAttribute)) as CustomAttribute; //This is always null for XX
}
}
public class MyClass
{
[CustomAttribute(MyProp1 = true, MyProp2="test")]
public bool X{ get ; set;},
[CustomAttribute(MyProp1 = true)]
public MyEnum XX{ get ; set;}
}
public enum MyEnum
{
ABC = 0,
XYZ = 1
}
public class CustomAttribute : Attribute
{
public bool MyProp1 { get; set; }
public string MyProp2 { get; set; }
}
This works just fine for me:
class Program
{
static void Main(string[] args)
{
var myClassProps = typeof(MyClass).GetProperties();
foreach (var prop in myClassProps.Where(p => p.Name == nameof(MyClass.XX)))
{
var attribs = prop.GetCustomAttributes(typeof(CustomAttribute), false);
if (attribs.Length > 0)
{
var customAttrib = attribs[0] as CustomAttribute;
//Do Something with it here
}
}
}
}
public enum MyEnum
{
ABC = 0,
XYZ = 1
}
public class CustomAttribute : Attribute
{
public bool MyProp1 { get; set; }
public string MyProp2 { get; set; }
}
public class MyClass
{
[Custom(MyProp1 = true, MyProp2 = "test")]
public bool X { get; set; }
[Custom(MyProp1 = true)]
public MyEnum XX { get; set; }
}
I'm not sure where you get the PropertyInfo.GetCustomAttribute, I couldn't find that member in PropertyInfo.
Related
I am writing a method for extracting all properties from an object (including properties of its own) with custom attribute . For example
public class SomeModel
{
[Custom]
public string Name { get; set; }
public string TestData { get; set; }
[Custom]
public string Surname { get; set; }
public InnerModel InnerModel { get; set; }
}
And Inner Model :
public class InnerModel
{
public string Id { get; set; } = "TestID";
[Custom]
public string Year { get; set; }
public ThirdObject HidedObject { get; set; }
}
And the third one :
public class ThirdObject
{
[Custom]
public string HidedName { get; set; }
}
I need to find all properties with "Custom" attribute .
Testing :
SomeModel model = new SomeModel()
{
Name = "farid",
Surname = "Ismayilzada",
TestData = "Test" ,
InnerModel = new InnerModel() { Year ="2022" , HidedObject= New ThirdObject{ HidedName="Secret"}}
};
I need to write the method
GetMyProperties(model) => List<PropInf>()
[PropertyName= Name,Value=Farid ,Route="Name" ]
[PropertyName= Surname,Value=Ismayilzada,Route="Surname" ]
[PropertyName= Year,Value=2022,Route="InnerModel.Year" ]
[PropertyName= HidedName,Value=Secret,Route="InnerModel.HidedObject.HidedName" ]
How to get this information ?
You can write a method like this :
private static IEnumerable<PropInfo> GetPropertiesInfo(object obj, string route = "")
{
List<PropInfo> results = new List<PropInfo>();
// You can filter wich property you want https://learn.microsoft.com/en-us/dotnet/api/system.reflection.propertyinfo?view=net-6.0
var objectProperties = obj.GetType().GetProperties().Where(p => p.CanRead);
foreach (var property in objectProperties)
{
var value = property.GetValue(obj);
if (property.PropertyType.IsClass && property.PropertyType != typeof(string))
{
results.AddRange(GetPropertiesInfo(value, route + property.Name + "."));
}
else
{
// Check if the property has the Custom Attribute
var customAttributes = property.GetCustomAttributes<CustomAttribute>();
if (!customAttributes.Any())
continue;
// You can set a method in your Attribute : customAttributes.First().CheckIfNeedToStoreProperty(obj);
results.Add(new PropInfo()
{
PropertyName = property.Name,
Value = value,
Route = route + property.Name
});
}
}
return results;
}
public class PropInfo
{
public string PropertyName { get; set; }
public object Value { get; set; }
public string Route { get; set; }
}
public class CustomAttribute : Attribute
{
public bool CheckIfNeedToStoreProperty(object obj)
{
return true;
}
}
i am working on source generator and i need to read properties data type as string
Is there any solution to get data type name such as int, string, bool, etc...?
EDIT:
var typeName = property.Type.ToString(); throws exception
EDIT 2:
public void Execute(GeneratorExecutionContext context)
{
var model = new TemplateModel();
var syntaxReceiver = (SolnetParsableClassExplorer)context.SyntaxReceiver;
syntaxReceiver?.SolnetDtos.ForEach(dto =>
{
var typeNodeSymbol = context.Compilation
.GetSemanticModel(dto.SyntaxTree)
.GetDeclaredSymbol(dto);
var dataClass = new DataClassModel();
foreach (var member in dto.DescendantNodes())
{
if (member is PropertyDeclarationSyntax property)
{
dataClass.AddProperty(property);
}
}
dataClass.ClassName = dto.Identifier.ValueText;
model.DataClassModels.Add(dataClass);
});
...
}
internal class SolnetParsableClassExplorer : ISyntaxReceiver
{
public List<ClassDeclarationSyntax> SolnetDtos { get; } = new();
public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
{
if (syntaxNode is ClassDeclarationSyntax classSyntax &&
classSyntax.HaveAttribute("SolnetDto"))
{
SolnetDtos.Add(classSyntax);
}
}
}
internal class DataClassModel
{
public List<DataField> Properties = new List<DataField>();
public string Namespace { get; set; }
public string ClassName { get; set; }
public int Size => Properties.Sum(p => p.Size);
public void AddProperty(PropertyDeclarationSyntax property)
{
// Here generator throw exception
var typeName = property.Type.ToString();
Properties.Add(
new DataField
{
PropertyName = property.Identifier.ValueText,
DataType = typeName,
Size = GetPropertySize(compilation, property, typeName),
WriteMethod = GetWriteMethod(typeName),
ReadMethod = GetReadMethod(typeName),
Offset = Size
});
}
I hope I understood your question correctly. To retrieve the string representation, you could use the TypeSyntax.ToString()
var strType = propertyDeclarationSyntax.Type.ToString();
For example, for the following
public string Bar1 { get; set; }
public int Bar2 { get; set; }
public long Bar3 { get; set; }
Result
Property Bar1 : string
Property Bar2 : int
Property Bar3 : long
I have this:
public class Blah
{
public int id { get; set; }
public string blahh { get; set; }
}
public class Doh
{
public int id { get; set; }
public string dohh { get; set; }
public string mahh { get; set; }
}
public List<???prpClass???> Whatever(string prpClass)
where string prpClass can be "Blah" or "Doh".
I would like the List type to be class Blah or Doh based on what the string prpClass holds.
How can I achieve this?
EDIT:
public List<prpClass??> Whatever(string prpClass)
{
using (var ctx = new ApplicationDbContext())
{
if (prpClass == "Blah")
{
string queryBlah = #"SELECT ... ";
var result = ctx.Database.SqlQuery<Blah>(queryBlah).ToList();
return result;
}
if (prpClass == "Doh")
{
string queryDoh = #"SELECT ... ";
var result = ctx.Database.SqlQuery<Doh>(queryDoh).ToList();
return result;
}
return null
}
}
you have to have a common supertype:
public interface IHaveAnId
{
int id { get;set; }
}
public class Blah : IHaveAnId
{
public int id { get; set; }
public string blahh { get; set; }
}
public class Doh : IHaveAnId
{
public int id {get;set;}
public string dohh { get; set; }
public string mahh { get; set; }
}
then you can do:
public List<IHaveAnId> TheList = new List<IHaveAnId>();
and in some method:
TheList.Add(new Blah{id=1,blahh = "someValue"});
TheList.Add(new Doh{id =2, dohh = "someValue", mahh = "someotherValue"});
to iterate through the list:
foreach(IHaveAnId item in TheList)
{
Console.WriteLine("TheList contains an item with id {0}", item.id);
//item.id is allowed since you access the property of the class over the interface
}
or to iterate through all Blahs:
foreach(Blah item in TheList.OfType<Blah>())
{
Console.WriteLine("TheList contains a Blah with id {0} and blahh ='{1}'", item.id, item.blahh);
}
Edit:
the 2 methods and a int field holding the autovalue:
private int autoValue = 0;
public void AddBlah(string blahh)
{
TheList.Add(new Blah{id = autovalue++, blahh = blahh});
}
public void AddDoh(string dohh, string mahh)
{
TheList.Add(new Doh{id = autovalue++, dohh = dohh, mahh = mahh});
}
Another Edit
public List<object> Whatever(string prpClass)
{
using (var ctx = new ApplicationDbContext())
{
if (prpClass == "Blah")
{
string queryBlah = #"SELECT ... ";
var result = ctx.Database.SqlQuery<Blah>(queryBlah).ToList();
return result.Cast<object>().ToList();
}
if (prpClass == "Doh")
{
string queryDoh = #"SELECT ... ";
var result = ctx.Database.SqlQuery<Doh>(queryDoh).ToList();
return result.Cast<object>.ToList();
}
return null;
}
}
in the view you then have to decide what type it is. In asp.net MVC you can use a display template and use reflection to get a good design. But then i still don't know what technology you are using.
Yet another Edit
TestClass:
public class SomeClass
{
public string Property { get; set; }
}
Repository:
public static class Repository
{
public static List<object> Whatever(string prpClass)
{
switch (prpClass)
{
case "SomeClass":
return new List<SomeClass>()
{
new SomeClass{Property = "somestring"},
new SomeClass{Property = "someOtherString"}
}.Cast<object>().ToList();
default:
return null;
}
}
}
And a controller action in mvc:
public JsonResult Test(string className)
{
return Json(Repository.Whatever("SomeClass"),JsonRequestBehavior.AllowGet);
}
then i called it with: http://localhost:56619/Home/Test?className=SomeClass
And got the result:
[{"Property":"somestring"},{"Property":"someOtherString"}]
Is this what you are trying to do?
public class Blah
{
public int id { get; set; }
public string blahh { get; set; }
}
public class Doh
{
public int id { get; set; }
public string dohh { get; set; }
public string mahh { get; set; }
}
class Program
{
public static List<T> Whatever<T>(int count) where T: new()
{
return Enumerable.Range(0, count).Select((i) => new T()).ToList();
}
static void Main(string[] args)
{
var list=Whatever<Doh>(100);
// list containts 100 of "Doh"
}
}
I have a class Class1
public class Class1
{
public string ABC { get; set; }
public string DEF { get; set; }
public string GHI { get; set; }
public string JLK { get; set; }
}
How can I get a list of, in this case 'ABC', 'DEF', ...
I want to get the name of all public fields.
I tried the following:
Dictionary<string, string> props = new Dictionary<string, string>();
foreach (var prop in classType.GetType().GetProperties().Where(x => x.CanWrite == true).ToList())
{
//Console.WriteLine("{0}={1}", prop.Name, prop.GetValue(classitem, null));
//objectItem.SetValue("ABC", "Test");
props.Add(prop.Name, "");
}
And:
var bindingFlags = BindingFlags.Instance |
BindingFlags.NonPublic |
BindingFlags.Public;
var fieldValues = classType.GetType()
.GetFields(bindingFlags)
.Select(field => field.GetValue(classType))
.ToList();
But neither gave me the wanted results.
Thanks in advance
Try something like this:
using System;
using System.Linq;
public class Class1
{
public string ABC { get; set; }
public string DEF { get; set; }
public string GHI { get; set; }
public string JLK { get; set; }
}
class Program
{
static void Main()
{
// Do this if you know the type at compilation time
var propertyNames
= typeof(Class1).GetProperties().Select(x => x.Name);
// Do this if you have an instance of the type
var instance = new Class1();
var propertyNamesFromInstance
= instance.GetType().GetProperties().Select(x => x.Name);
}
}
Isn't clear what classType means in your original code.
If it's a instance of Class1 that should work; if you already got a System.Type, your classType.GetType() will not return your properties.
Also, you should be aware of properties and fields difference, as it matters to reflection. The code below lists your original properties, skips a property without setter and also a field, just to demonstrate how that conceptual difference affects your code.
class Program
{
static void Main(string[] args)
{
var classType = typeof (Class1);
foreach (var prop in classType.GetProperties().Where(p => p.CanWrite))
{
Console.WriteLine(prop.Name);
}
foreach (var field in classType.GetFields())
{
Console.WriteLine(field.Name);
}
}
}
public class Class1
{
public string ABC { get; set; }
public string DEF { get; set; }
public string GHI { get; set; }
public string JLK { get; set; }
public string CantWrite { get { return ""; } }
public string Field = "";
}
I've the following attribute:
class HandlerAttribute : System.Attribute
{
public string MainName { get; private set; }
public string SubName { get; private set; }
public HandlerAttribute(string pValue, bool pIsMain) {
if (pIsMain) MainName = pValue;
else SubName = pValue;
}
}
And this is the way I use the attribute
[Handler("SomeMainName", true)]
class Class1 {
[Handler("SomeSubName", false)]
void HandleThis() {
Console.WriteLine("Hi");
}
}
What I want to achieve is that I import the MainName value from the parent class attribute into the method defined inside the class.
I hope that someone can help me with this :)
Thanks in advance
I would advice to write a helper method for this, basically it isn't possible by default because you don't have access to the attribute's target.
Code
[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
sealed class HandlerAttribute : Attribute
{
public string MainName { get; private set; }
public string SubName { get; private set; }
public HandlerAttribute(string pValue, bool pIsMain) {
if (pIsMain) MainName = pValue;
else SubName = pValue;
}
public HandlerAttributeData GetData(MemberInfo info)
{
if (info is Type)
{
return new HandlerAttributeData(MainName, null);
}
HandlerAttribute attribute = (HandlerAttribute)info.DeclaringType.GetCustomAttributes(typeof(HandlerAttribute), true)[0];
return new HandlerAttributeData(attribute.MainName, SubName);
}
}
class HandlerAttributeData
{
public string MainName { get; private set; }
public string SubName { get; private set; }
public HandlerAttributeData(String mainName, String subName)
{
MainName = mainName;
SubName = subName;
}
}
Usage
HandlerAttribute att = (HandlerAttribute)typeof(App).GetCustomAttributes(typeof(HandlerAttribute), true)[0];
HandlerAttributeData data = att.GetData(typeof(App));
You can use it with any member and if you write a extension method you can make it even shorter.
Update:
You may use this extension method as well.
public static class AttributeExtensions
{
public static string GetMainName(this Class1 class1)
{
System.Attribute[] attrs = System.Attribute.GetCustomAttributes(class1.GetType()); // reflection
foreach (System.Attribute attr in attrs)
{
if (attr is HandlerAttribute)
{
string mainName = (attr as HandlerAttribute).MainName;
return mainName;
}
}
throw new Exception("No MainName Attribute");
}
}
Now after coding the extension method you may use it on any Class1 type object;
Class1 c1 = new Class1();
string a =c1.GetMainName();
Or you may use it directly.
public class HandlerAttribute : System.Attribute
{
public string MainName { get; private set; }
public string SubName { get; private set; }
public HandlerAttribute(string pValue, bool pIsMain)
{
if (pIsMain) MainName = pValue;
else SubName = pValue;
}
}
[Handler("SomeMainName", true)]
class Class1
{
[Handler("SomeSubName", false)]
public void HandleThis()
{
System.Attribute[] attrs = System.Attribute.GetCustomAttributes(this.GetType()); // reflection
foreach (System.Attribute attr in attrs)
{
if (attr is HandlerAttribute)
{
string mainName = (attr as HandlerAttribute).MainName;
}
}
}
}