In the list of objects of type
List<Configuracion.Models.v_cCfgDeclaraciones>
I would like retrive the name field, I would like to find the name of the field within the loop (foreach) better if I do not use reflection, how i can resolve this?
Put together something on Linqpad. Note that this does use reflection:
void Main() {
Test t = new Test();
Type tType = t.GetType();
foreach (PropertyInfo prop in tType.GetProperties()) {
prop.Name.Dump();
}
}
public class Test {
public string prop1 { get; set; }
public string prop2 { get; set; }
public Test() {
prop1 = "Property 1";
prop2 = "Property 2";
}
}
I don't know of a way you can get this information (short of hard-coding it in) without using reflection. Is there a reason you don't want to use reflection in this case?
Related
I am using C# 4.5 and ASP.NET MVC 5.
I have the following:
[Required(ErrorMessage = "Prop1 is required")]
public string Prop1 { get;set;}
[Required(ErrorMessage = "Prop2 is required")]
public string Prop2 { get;set;}
As you see the error message is the property name plus the " is required" string. What I need is instead of typing the property name and the message for every property, use a generic method composer, that will return the name of the decorated property and a string that I add, something like:
public string GetMessage()
{
// Caller property should be a variable that is retrieved dynamically
// that holds the name of the property that called the function
return CallerProperty + " is required";
}
so now I can user:
[Required(ErrorMessage = GetMessage())]
public string Prop2 { get;set;}
so in brief: How can I know the property name that is decorated by an attribute.
Use reflection.
Pseudo
public List<Required> CallerProperty<T>(T source)
{
List<Required> result = new List<Required>();
Type targetInfo = target.GetType();
var propertiesToLoop = source.GetProperties();
foreach (PropertyInfo pi in propertiesToLoop)
{
Required possible = pi.GetCustomAttribute<Required>();
if(possible != null)
{
result.Add(possible);
string name = pi.Name; //This is the property name of the property that has a required attribute
}
}
return result;
}
This is just a demo of how to capture a custom attribute on a property. You have to work out how to manage a list of them, or whatever you need in order to generate the return type you need. Perhaps map it with the "pi.Name" also referenced? I don't know precisely what you need.
You can use the "nameof" expression as follows:
class Class1
{
[CustomAttr("prop Name: " + nameof(MyProperty))]
public int MyProperty { get; set; }
}
public class CustomAttr : Attribute
{
public CustomAttr(string test)
{
}
}
I have a little problem, below my code:
public class A
{
public string ObjectA { get; set; }
}
public void Run()
{
A a = new A();
a.ObjectA = "Test number 1";
BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
PropertyInfo myPropertyInfo = a.GetType().GetProperty("ObjectA", flags);
object myNewObject = myPropertyInfo.GetValue(a);// Here should be reference
a.ObjectA = "Test number 2";//After this line value myNewObject continued "Test number 1"
}
So my value myNewObject must be in output "Test number 2". Is there any way? It is this at all possible?
Wrong!
You're getting the string rather than the instance of A using reflection.
Changing A.ObjectA doesn't change the string reference. Actually, you're setting a different string to the backing string class field by the ObjectA property...
Auto-properties are syntactic sugar to avoid explicitly declaring class fields to properties which perform nothing when getting or setting their values:
// For example:
public string Text { get; set; }
// is...
private string _text;
public string Text { get { return _text; } set { _text = value; } }
Now turn your code into regular one (no reflection):
A a = new A();
a.ObjectA = "hello world";
object myNewObject = a.ObjectA;
// Do you think now that myNewObject should change...? :)
a.ObjectA = "goodbye";
Is there any way? It is this at all possible?
No.
Maybe you can simulate this behavior using a Func<T>...
Func<object> myNewObjectGetter = () => myPropertyInfo.GetValue(a);
Now, whenever you call myNewObjectGetter() you're going to get the most fresh value of the whole property. BTW, this still doesn't address the impossible!
Is there any way?
No. You can't put a reference to a property into an object variable. Such a variable can only hold a normal value, such as the string you put into it.
That answers the question as asked. You can clarify what you want to achieve and maybe we can suggest a better way.
Probably there is no solution but I show some code
public class MyRows
{
public string Key { get; set; }
public int Id { get; set; }
public object Val { get; set; }
}
public abstract class BasicDTO
{
public int? Id { get; private set; }
public PropertyInfo[] PropertyDTO;
protected Type myType;
public BasicDTO()
{
Load();
BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
PropertyDTO = myType.GetProperties(flags);
}
}
public class CustomerDTO : BasicDTO
{
public string Surname { get; set; }
public string Phone { get; set; }
public CustomerDTO() { }
protected override void Load()
{
myType = typeof(CustomerDTO);
}
}
Now my basic method
public void Run(BasicDTO dto)
{
PropertyInfo pi = dto.PropertyDTO.Where(x => x.Name == "Surname").SingleOrDefault();
MyRows mr = new MyRows();
mr.Val = pi.GetValue(dto);//Here I need reference
}
When I change CustomerDTO.Surname my value mr.Val it must also be changed.
As I wrote above, it is probably impossible, but maybe anybody have a idea.
BTW: Value mr.Val I use only for binding (WPF). So maybe you have any other suggestions, how solve problem. I will be grateful for your help
Ok so I have been up and down the internet looking for a solution to this question. I think my title is maybe no to informative so some background.
I have the following classes:
public class foo { public string Name { get; set; } }
public class foo1 { public string Name { get; set; } }
public class foo2 { public string Name { get; set; } }
public class foo3 { public string Name { get; set; } }
public class foo4 { public string Name { get; set; } }
public class foo5 { public string Name { get; set; } }
public class goo
{
public string Desc { get; set; }
public foo f { get; set; }
public foo1 f1 { get; set; }
public foo2 f2 { get; set; }
public foo3 f3 { get; set; }
public foo4 f4 { get; set; }
}
So now my question, Using Reflection, how can I get to the value of foo.Name when only having a reference to goo.
The normal Reflection code is:
goo g = new goo();
PropertyInfo pInfo = g.GetType().GetProperty("Name");
string Name = (string)pInfo.GetValue(g, null);
So the above code is how you get a property from the goo class. But now how do you get the value of foo.Desc?
I tried the following which doesn't work:
goo g = new goo();
PropertyInfo pInfo = g.GetType().GetProperty("f");
PropertyInfo pInfo2 = pInfo.PropertyType.GetProperty("Desc");
string Name = (string)pInfo2.GetValue(pInfo.PropertyType, null);
Unfortunately I get a Mismatched object error which I can understand because I am trying to use the property type and not the actual instance of the foo class. I also tried to fins a way to instantiate an object from the propertyinfo but if there is a way then it eludes me. I could do something like this:
goo g = new goo();
PropertyInfo propInfo = g.GetType().GetProperty("f");
object tmp;
propInfo.SetValue(g, Convert.ChangeType(new foo(), propInfo.PropertyType), null);
tmp = g.f;
This works but besides having to hard code the class, that is creating a new instance and therefore of now use to me.
As I say I have been up and down looking for a solution. Everything I have found is basically variants on the "get a value of a property of a class" theme but nothing about going another level deeper.
Can anyone help? Is this even possible because I would really like to stay away from hard coding.
EDIT: I have edited the class to more accurately represent what I am working with. Based on the comments below, I am getting the names of the foo instances from a database and that is why I am using Reflection or want to use Reflection instead of hard coding 30+ switch statements.
EDIT: Also I don't know before runtime which foo classes will be populated with data. Also each foo class is different. Unlike my example where each foo class has a string property, in my project each class has a different design which mirrors the database.
EDIT: So Ulugbek Umirov gave the answer. I just didn't see it immediately. Below my implementation so as to maybe help others in the future.
foreach (PropertyInfo pInfo in _standard.GetType().GetProperties())
{
if (_fullDataModel.ClassDefinitions.Contains(pInfo.Name))
{
PropertyInfo _std_pinfo = _standard.GetType().GetProperty(pInfo.Name);
object g = _std_pinfo.GetValue(_standard, null);
PropertyInfo props = g.GetType().GetProperty("showMe");
bool showMe = (bool)props.GetValue(g, null);
if (showMe)
{
string tblName = _fullDataModel.ClassDefinitions[pInfo.Name]. PropertyGroupDefinitions.Where(p => p.TransactionsTable != true).First().Token;
// Use tblName to build up a dataset
}
}
}
This does exactly what I wanted.
Thank you.
Given your current code you can do the following:
goo g = new goo();
g.f = new foo { Name = "Hello" };
PropertyInfo pInfo = g.GetType().GetProperty("f");
object f = pInfo.GetValue(g);
PropertyInfo pInfo2 = f.GetType().GetProperty("Name");
string name = (string)pInfo2.GetValue(f);
You can set arbitrary property as well:
goo g = new goo();
PropertyInfo pInfo = g.GetType().GetProperty("f");
object f = Activator.CreateInstance(pInfo.PropertyType);
PropertyInfo pInfo2 = f.GetType().GetProperty("Name");
pInfo2.SetValue(f, "Hello");
pInfo.SetValue(g, f);
Similar: How I can find Data Annotation attributes and their parameters using reflection
However, when attempting to gather the custom attribute, I always get back the same result. An empty ScriptIgnore.
PropertyInfo[] Properties = Entity.GetType().GetProperties();
foreach (PropertyInfo Property in Properties)
Upon debug, this line of code
var annotes = Property.GetCustomAttributes(typeof(ScriptIgnoreAttribute), false);
(I also tried using true)
looks like this
annotes | {System.Web.Script.Serialization.ScriptIgnoreAttribute[0]}
However, Property is defined as a class property like this
public virtual Lot Lot { get; set; }
There is no [ScriptIgnore] attribute attached. Moreover, when I have tried this on Property when it was defined like this
[ScriptIgnore]
public virtual ICollection<Lot> Lots { get; set; }
I get back the same result as above
annotes | {System.Web.Script.Serialization.ScriptIgnoreAttribute[0]}
How can I use reflection to determine if an attribute exists? Or other means if possible, I also tried
var attri = Property.Attributes;
but it did not contain any attributes.
The following code works:
using System.Web.Script.Serialization;
public class TestAttribute
{
[ScriptIgnore]
public string SomeProperty1 { get; set; }
public string SomeProperty2 { get; set; }
public string SomeProperty3 { get; set; }
[ScriptIgnore]
public string SomeProperty4 { get; set; }
}
Define a static extension:
public static class AttributeExtension
{
public static bool HasAttribute(this PropertyInfo target, Type attribType)
{
var attribs = target.GetCustomAttributes(attribType, false);
return attribs.Length > 0;
}
}
Put the following sample code into a method and it picks up the attribute correctly - including ICollection by the way:
var test = new TestAttribute();
var props = (typeof (TestAttribute)).GetProperties();
foreach (var p in props)
{
if (p.HasAttribute(typeof(ScriptIgnoreAttribute)))
{
Console.WriteLine("{0} : {1}", p.Name, attribs[0].ToString());
}
}
Console.ReadLine();
NOTE: if you're using EF dynamic proxy classes, I think you will need to use ObjectContext.GetObjectType() to resolve to the original class before you can get the attributes, since the EF-generated proxy class will not inherit the attributes.
var props = type.GetProperties()
.Where(p => p.GetCustomAttributes().Any(a => a is ScriptIgnoreAttribute))
.ToList();
My problem is quite simple
Suppose I have those class:
public class A
{
public Collection<B> B { get; set; }
public Collection<C> C { get; set; }
}
public class B
{
public int IntB { get; set; }
}
public class C
{
public string StringC { get; set; }
}
And I write a function:
public void GetValue(string fieldName){
A a = new A();
PropertyInfo infor = typeof(A).GetProperty(fieldName);
object obj = infor.GetValue(a,null);
}
My question is how can I turn obj to corresponding Collection, in this case is Collection<B> or Collection<C>, depending in fieldName value
Thank in advance
You can cast it:
var collection = (Collection<B>)(infor.GetValue(a,null));
EDIT:
if you use LINQ on the resulting collections, you may want to use OfType (link: http://msdn.microsoft.com/en-us/library/bb360913.aspx) and/or Cast (link: http://msdn.microsoft.com/en-us/library/bb341406.aspx)
Like
var collection = getCollection(a,null));
collection.OfType<B>.Select(b => b.IntB)....
You can't have a statically typed object in your method when you determine the property that will be called at runtime. But the runtime time of obj is of the actual type of your property.