Why does GetFields() not return anything? - c#

I am trying to retrieve the public properties of an object but it is returning nothing. Can you tell me what I'm doing wrong.
public class AdHocCallReportViewModel : ReportViewModel
{
public string OperatorForCustEquipID { get; set; }
public string OperatorForPriorityID { get; set; }
public string OperatorForCallTypeID { get; set; }
public string OperatorForStatusID { get; set; }
}
public UpdateReportParameters(AdHocCallReportViewModel rvm)
{
var type = rvm.GetType();
foreach (var f in type.GetFields().Where(f => f.IsPublic))
{
Console.WriteLine(f.Name);
Console.WriteLine(f.GetValue(rvm).ToString());
}
}
When stepping through the code, it skips over the foreach loop because GetFields returns zero items.

You haven't got public fields. They are properties. So try type.GetProperties() instead.

You are trying to get fields, you should try to call GetProperties()

Pass BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public to get all instance fields.
On second thought, I'm seeing that you are explicitly filtering for public fields. The class does not have any public fields. The fields that are automatically generated by the compiler as the backing store for the properties are private.

Related

How to implement reflection to get an object field based on a generic enum

I think it is a rather simple issue, but I can't really get my head around reflection things.
I'm looking for a way to initialize DropDownList based on enums with default value in Razor page
I have the following CustomModel class which have many enum properties:
public class CustomModel {
public EnumA A { get; set; }
public EnumB B { get; set; }
// Other properties based on EnumC, EnumD, etc.
}
And the view model where I want to populate each enum:
public class CustomViewModel
{
public CustomModel Custom { get; set; }
public SelectList As { get; set; }
public SelectList Bs { get; set; }
// Other SelectList properties for all the different enums
public CustomViewModel(CustomModel custom) // Will need to think about some dependency injection
{
Custom = custom;
As = InitializeDropDownList<A>();
Bs = InitializeDropDownList<B>();
// Idem for all other enums
}
// Probably move it to an extension method
private SelectList InitializeDropdownList<T>() where T : struct, Enum
{
// string value = ...
new SelectList(new Descriptions<T>(), value)
}
}
// Returns the string values corresponding to the generic enum
public class Descriptions<T> : List<string> where T : struct, Enum
{
public Descriptions()
{
// Enumerates the T values
foreach (T e in Enum.GetValues(typeof(T)))
{
// A bit simplified, because I actually use an other Description extension method
Add(e.ToString());
}
}
}
Is there a way to get the value in the InitializeDropdownList function using generics and reflection as follows :
T = EnumA => value = CustomModel.A
T = EnumB => value = CustomModel.B
...
I think I should use FieldInfo[] fields = Custom.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); and compare it to the actual name of T and then get the value of the field whih I don't know how to do. Does anyone have an idea of how to achieve it?
Thanks for any insights!

how to iterate reference variable inside a class

I tried to use the code PropertyInfo[] but the code is not getting any attribute. Because the attribute inside class1 is just a reference variable
public readonly subClass1 sClass1;
public readonly subClass2 sClass2;
public readonly subClass3 sClass3;
public class1()//constructor
{
sClass1= new subClass1();
sbClass2= new subClass2();
sClass3= new subClass3();
}
My problem is, i can't access those 3 classes just by using PropertyInfo[]
but my i can access it using
Type type = typeof(class1);
FieldInfo[] fields = type.GetFields();
var i = 0;
foreach (var field in fields)
{
var f = field.GetType().GetFields();
i++;
}
But this code is not working as i want to work, they can get the class but i can't get the property of every subClass
What i want is something like this
var f = class1.sClass1;
my variable f will now hold the every property of a class.
I'm sorry if i can't explain it well. If you want to ask something, just comment below
by the way this is the inside code of every subClass
public string X{ get; set; }
public string Y{ get; set; }
public string Width { get; set; }
public string Length { get; set; }
You will have to do it recursively
void GetFields(Type type)
{
foreach (FieldInfo fieldInfo in type.GetFields(BindingFlags.Instance
| BindingFlags.Public | BindingFlags.NonPublic)) {
Console.WriteLine("{0} {1}", fieldInfo.FieldType.Name, fieldInfo.Name);
if (fieldInfo.FieldType.IsClass)
GetFields(fieldInfo.FieldType);
}
You have to use field.FieldType instead of using field.GetType()

Get object reference from PropertyInfo

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

Return a List<SomeObject> without a certain property using Linq in c#?

I have an object containing different properties like the object below:
public class CompressedLogResponse
{
public string LoggerType { get; set; }
public int NumberOfRegisters { get; set; }
public int NewLogId { get; set; }
public DateTime LoggerAnnounceTime { get; set; }
public List<Log> Log{ get; set; }
}
How can I return a List of this objekt that does not include the List<Log> Log property?
Linq would be preffered
Thanks for any help that you can provide
You cannot just hide a property of a class (you declared it a as public)
Option 1:
Althought as Robson wrote you can set it null (thats not very reliable thaught cause nobody expects a class containing a property that is always null)
Option2:
If you consume the class on the same place use a anonymous type as Mez wrote, althought it sounds like you want to hide the Property from external usage. (I don't like the dynamic approach, the dynamic keyword was made for interop/DOM not for transporting anonymous types.)
Option3:
If you want a List of this type to be returned without the Log property, you have to create a new class (Inheritance is a good way to realize this):
public class CompressedLogResponseBase
{
public string LoggerType { get; set; }
public int NumberOfRegisters { get; set; }
public int NewLogId { get; set; }
public DateTime LoggerAnnounceTime { get; set; }
}
public class CompressedLogResponse : CompressedLogResponseBase
{
public List<Log> Log{ get; set; }
}
Now you can return a list of base items (that do not have a Log property at all)
public List<CompressedLogResponseBase> ReturnWithoutLog(IEnumerable<CompressedLogResponse> items)
{
return ((IEnumerable<CompressedLogResponseBase>)items).ToList();
}
If a IEnumerable as return type is suficient it becomes really easy
public IEnumerable<CompressedLogResponseBase> ReturnWithoutLog(IEnumerable<CompressedLogResponse> items)
{
return items
}
whith "does not include the List Log property" i guess you mean that the property "public List Log" will be blanked but still there, so you can just null that property out, because if you create an object that doesn't contain the "public List Log" property, than it will not be a "CompressedLogResponse" but will be another type.
List<CompressedLogResponse> listOne = new List<CompressedLogResponse>();
//....
//fill the listOne
//....
List<CompressedLogResponse> listWithoutListLog = (from item in listOne
select new CompressedLogResponse(
LoggerType = item.LoggerType,
NumberOfRegisters = item.NumberOfRegisters ,
NewLogId = item.NewLogId ,
LoggerAnnounceTime = item.LoggerAnnounceTime ,
Log= null)).ToList();
You can return an anonymous list of your original list like the following;
public static List<dynamic> Test() {
List<CompressedLogResponse> list = new List<CompressedLogResponse>();
var result = list.Select(x => new
{
x.LoggerAnnounceTime,
x.LoggerType,
x.NewLogId,
x.NumberOfRegisters
});
return result.ToList<dynamic>();
}
Take a look at the .Select(), and also the dynamic keyword.
Then to call it,
var x = Test();
foreach(dynamic o in x)
{
int NumberOfRegisters;
//You have 2 ways... either by
NumberOfRegisters = o.NumberOfRegisters;
// or reflection
NumberOfRegisters = o.GetType().GetProperty("NumberOfRegisters").GetValue(o, null);
}

C# Reflection and Attributes: Bug? I can't get around this

This is in the Immediate console:
prop.GetCustomAttributes(typeof(RequiredParameterAttribute),true)
{BridgeStack.DataContracts.RequiredParameterAttribute[0]}
prop.GetCustomAttributes(typeof(RequiredParameterAttribute),true).Cast<RequiredParameterAttribute>()
{BridgeStack.DataContracts.RequiredParameterAttribute[0]}
[BridgeStack.DataContracts.RequiredParameterAttribute[]]: {BridgeStack.DataContracts.RequiredParameterAttribute[0]}
prop.GetCustomAttributes(typeof(RequiredParameterAttribute),true).Cast<RequiredParameterAttribute>().Any()
false
I get the same results in the application.
prop is Site in:
public class AnswerCollectionQuery : IPagedQuery, ISiteQuery, ISortableQuery, IOrderableQuery, IFilteredQuery
{
public int? Page { get; set; }
public int? PageSize { get; set; }
public string Site { get; set; }
[AllowedSortValues(QuerySortEnum.Activity, QuerySortEnum.Creation, QuerySortEnum.Votes)]
public QuerySortEnum? Sort { get; set; }
public object Min { get; set; }
public object Max { get; set; }
public DateTime? FromDate { get; set; }
public DateTime? ToDate { get; set; }
public QueryOrderEnum? Order { get; set; }
public string Filter { get; set; }
}
Site in turn comes from ISiteQuery
public interface ISiteQuery : IQuery
{
[RequiredParameter]
string Site { get; set; }
}
The awkward part is that the console shows the attribute, allows me to cast it, but I can't retrieve it at all, I get zero as the enumeration's length, which is why .Any() fails, too, .FirstOrDefault() returns null, .First() throws, etc.
Any explanation for this type of behavior?
PD: this works though if I decorate Site with [RequiredAttribute] in the concrete class. But I wanted to make this part of the interface.
Update for clarity:
prop comes exactly from here:
public static IEnumerable<PropertyInfo> GetAllProperiesOfObject(object o)
{
const BindingFlags flags = BindingFlags.Public | BindingFlags.FlattenHierarchy | BindingFlags.Instance;
PropertyInfo[] list = o.GetType().GetProperties(flags);
return list;
}
foreach (PropertyInfo prop in Utility.GetAllProperiesOfObject(entity))
This is the case for when prop becomes Site
The zero is because it is returning you a zero-length typed array, meaning: it doesn't have the attribute. You can also see this with Attribute.IsDefined (which will return false).
When using implicit interface implementation, the public property on the class does not automatically gain attributes from the interface that it satisfies. To see the attributes on the interface you would need to use
typeof(ITheInterface).GetProperties()
The Site property on the interface is unrelated to the Site property on the class. If the property on the class must have attributes: add the attributes explicitly.

Categories

Resources