I got two classes, and i want to use reflection.
public Class A
{
public string aa { get; set; }
public string bb { get; set; }
...
}
public Class B: A {}
when i try to get the Property of an B object i got no properties;
TypeInfo b = typeof(B).GetTypeInfo();
IEnumerable<PropertyInfo> pList = b.DeclaredProperties;
pList is always null, maybe because i used "DeclaredProperties" instead of GetProproperties(), but in winRt i can't use it.
i've read this solution How to get properties of a class in WinRT but i can't use var properties = this.GetType().GetTypeInfo().GetRuntimeProperties(); because GetRuntimeProperties() is not recognized
Solution Found, doubts still remain
To get the property of an inherited class i need to get the RuntimeProperties in this way
IEnumerable<PropertyInfo> pList = typeof(B).GetRuntimeProperties();
ignoring the PropertyInfo, and it works too if i try to get the property of an A object
What are the differences between getType().GetTypeInfo() and getType().GetRuntimeProperties() while i'm reading the property of an A object?
public string aa;
public string bb;
These are not properties. Properties are defined such as:
public string Aa
{
get;
set;
}
For more information, look up the official documentation on MSDN.
Once you've made the corrections to your classes A and B, you will be able to use :
var classProperties = typeof(B).GetTypeInfo().DeclaredProperties;
For properties defined within the class B, and :
var allProperties = typeof(B).GetRuntimeProperties();
For properties that are defined within the class and in its inheritance tree; i.e. properties that are actually accessible at runtime (therefore the name of the method).
If you don't want to change the public fields to properties (but you definitely should), use the GetRuntimeFields method on typeof(B) and DeclaredMembers on typeof(B).GetTypeInfo() for similar behaviour.
Related
I'm trying to convert some anonymous type back to its original strong type class.
I have some legacy code (which I cannot touch) which create an anonymous class:
public class Cat : FooId
{
public int Id { get; set; }
public string Name { get; set; }
}
var result = new
{
Id = Mapper.Map<TFooId>(someCat)
};
NOTE: I've tried to make this fake class and interface similar to my code.
This then gives me:
result.GetType().ToString() : <>f__AnonymousType1``1[MyProject.Cat]
From here, I'm not sure how to convert this back to a MyProject.Cat instance?
I've tried (and fails):
(MyProject.Cat)result
(dynamic)result
but both fail. The dynamic doesn't throw an error ... but I can't access any properties in it.
C# is a statically typed language, and those two types are not in any way related to one another. Unless you're able to modify the code which defines those types, the way you'd convert from one to the other would be to create a new instance of the target type and populate it from the source object.
For example:
var resultCat = new Cat { Id = result.Id };
Edit: From comments it looks like it may be possible that the Id property on the result object may be an instance of Cat or some other object? You're going to need to do some debugging to find out what your types are.
But the overall concept doesn't really change. If you have an instance of Cat in your results then you can use that instance. If you don't then in order to create one you'd need to create a new instance and populate it with the data you have. Even if two types are intuitively or semantically similar, they are different types.
It's true what David said with regard to the fact that C# is a statically-typed language and that the new instance should be populated from the source the way he suggested.
However, there are work-arounds (though less performant) for that, such as reflection.
Consider you have a console app where you have defined ObjectExtensions as follows:
public static class ObjectExtensions
{
public static TOut Map<TOut>(this object #in)
where TOut : new()
{
TOut #out = new TOut();
if (#in?.GetType() is Type tin)
{
Type tout = typeof(TOut);
foreach ((PropertyInfo pout, PropertyInfo pin) in tout.GetProperties().Join(tin.GetProperties(), pi => pi.Name, pi => pi.Name, (pout, pin) => (pout, pin)))
{
pout.SetValue(#out, pin.GetValue(#in));
}
}
return #out;
}
}
And Class1 as follows:
public class Class1
{
public string A { get; set; } = "A";
public string B { get; set; } = "B";
public string C { get; set; } = "C";
public override string ToString()
{
return $"{{A={A}, B={B}, C={C}}}";
}
}
You will be able to map your anonymous type back to its original strongly-typed class like this:
Console.WriteLine(new { A = "Anonymous A", B = "Anonymous B", C = "Anonymous C" }.Map<Class1>());
Therefore the bloc above should show the following output:
{A=Anonymous A, B=Anonymous B, C=Anonymous C}
In this case, of course, I have assumed that Class1 (Cat in your example) must have a public parameterless constructor. That may not always be the case. There are more sophisticated scenarios of course that might involve other techniques for creating the object such as cloning or dependency injection. Just saying that the idea of yours is possible.
I have the following class
[ProtoContract(ImplicitFields = ImplicitFields.AllFields)]
public class Foo
{
public int foo { get; set; }
[ProtoIgnore]
public Bar bar { get; set; }
public int ToMD5Hash()
{
var md5 = MD5CryptoServiceProvider.Create();
using (MemoryStream ms = new MemoryStream())
{
Serializer.Serialize<Foo>(ms, this);
var hash = md5.ComputeHash(ms.ToArray());
return BitConverter.ToInt32(hash, 0);
}
}
}
But I am getting an exception when calling ToMD5Hash. It says No serializer defined for type: SomeNamespace.Bar even if the property is decorated with the ProtoIgnore attribute.
Note: If I remove ImplicitFields and use ProtoMember, the serialization works.
Am I doing something wrong?
You've told it to serialize the fields. The field is not decorated with [ProtoIgnore]. The property is, and there is no good way to equate fields to properties. The use of the term "fields" here is very specific and intentional: it doesn't mean "members" - it means "fields".
Options:
tell it to serialize public members, not fields
use a manually implemented property and mark the field with [ProtoIgnore]
mark the members manually
It would be nice if automatically implemented properties allowed the same syntax as field-like events, i.e.
[field:ProtoIgnore]
public int Foo {get;set;}
However, I'm pretty sure that this is not supported in the language.
How can I project into class property using NHibernate? For example:
[Test]
public void Test()
{
MyClass dto = null;
var test = CurrentSession.CreateCriteria<Contact>()
.Add(Restrictions.Eq("ContactName", "John Smith"))
.SetProjection(Projections.ProjectionList()
.Add(Projections.Property("ContactName").WithAlias(() => dto.SubClass.Name))
.Add(Projections.Property("EmailAddress").WithAlias(() => dto.Email))
)
.SetResultTransformer(Transformers.AliasToBean<MyClass>())
.List<MyClass>();
Assert.That(test[0].SubClass.Name, Is.EqualTo("John Smith"));
}
class MyClass
{
public string Email { get; set; }
public MySubClass SubClass { get; set; }
}
class MySubClass
{
public string Name { get; set; }
}
As you see I have a simple query and want to transform 1 row into 1 object - without lists but with a subclass. Unfortunately, it fails:
NHibernate.PropertyNotFoundException : Could not find a setter for property 'Name' in class 'MyTest+MyClass'
Is it possible to achieve this behaviour without custom transformer?
The default result transformer will be able to fill the root entity properties. But we can introduce our custom result transformer. There is one I do use:
DeepTransformer<TEntity> : IResultTransformer
Which is ready to convert . notation into chain of inner objects (excluding collections)
So, if you'll take it, and reuse it, this syntax would work:
...
.SetProjection(Projections.ProjectionList()
.Add(Projections.Property("ContactName").As("SubClass.Name"))
.Add(Projections.Property("EmailAddress").As("Email"))
)
.SetResultTransformer(DeepTransformer<MyClass>())
You can even improve it, but the idea of custom transformer should be clear now
I have a search page which is using strongly typed objects, but I have the values broken into specific groups.
Code behind page calls the following when the user clicks the search button (none of these fields are empty):
SearchCriteria sc = new SearchCriteria();
sc.Generic.id = txtId.Text;
sc.Generic.maxReturned = rblMaxReturned.SelectedIndex;
sc.DisplayOnly.category = txtCategory.Text;
sc.DisplayOnly.type = txtType.Text;
sc.Building.address = txtAddress.Text;
sc.Building.city = txtCity.Text;
The DataType file is defined like this:
[Serializable]
public class SearchCriteria
{
public _Generic Generic { get;set; }
[Serializable]
public class _Generic
{
public int id {get;set;}
public int maxReturned {get;set;}
}
public _DisplayOnly DisplayOnly { get;set; }
[Serializable]
public class _DisplayOnly
{
public int category {get;set;}
public int type {get;set;}
}
public _Building Building { get;set; }
[Serializable]
public class _Building
{
public int address {get;set;}
public int city {get;set;}
}
}
When the code executes, I get a nullreferenceerror even though all the items in the various textboxes have a value. However, if I take out the public _Building Building { get;set; } and call the class directly it works and populates the values. What's the best solution here? Should I not use intermediary definition and call the class directly? If so, how can I call the different groups without making four different calls on the code behind page?
You need to initialize the internal class instances. Simply declaring the variables doesn't mean that you can access their properties without creating the instances. You could easily do that in the constructor of the SearchCriteria class
[Serializable]
public class SearchCriteria
{
public SearchCriteria()
{
// Without these initialization the internal variables are all null
// and so assigning any property of a null object causes the error
Generic = new _Generic();
DisplayOnly = new _DisplayOnly()
Building = new _Building();
}
.....
}
When you create a new instance of your SearchCriteria class, the properties are not initialized, and so they all have a value of null. So now look at the very first line where you try to use one of those properties:
sc.Generic.id = txtId.Text;
Here, txtID.Text is perfectly fine, but sc.Generic is null. When you try to look up the it's .id property for assignment, that's where the exception is thrown.
To fix this, you need to initialize each of those properties to have an instance of their type. Additionally, it's probably a good idea to use a private set, like so:
public _Generic Generic { get;private set; }
This will still allow to make all the same assignments that are currently written, because that only requires a get action to retrieve the type instance. The assignment/set operation is on the property of the property.
Can some one explain to me why the GetProperties method would not return public values if the class is setup as follows.
public class DocumentA
{
public string AgencyNumber = string.Empty;
public bool Description;
public bool Establishment;
}
I am trying to setup a simple unit test method to play around with
The method is as follows and it has all the appropriate using statements and references.
All I'm doing is calling the following but it returns 0
PropertyInfo[] pi = target.GetProperties(BindingFlags.Public | BindingFlags.Instance);
But if I setup the class with private members and public properties it works fine.
The reason I didn't setup up the the class the old school way was because it has 61 properties and doing that would increase my lines of code to at least triple that. I would be a maintenance nightmare.
You haven't declared any properties - you've declared fields. Here's similar code with properties:
public class DocumentA
{
public string AgencyNumber { get; set; }
public bool Description { get; set; }
public bool Establishment { get; set; }
public DocumentA()
{
AgencyNumber = "";
}
}
I would strongly advise you to use properties as above (or possibly with more restricted setters) instead of just changing to use Type.GetFields. Public fields violate encapsulation. (Public mutable properties aren't great on the encapsulation front, but at least they give an API, the implementation of which can be changed later.)
Because the way you have declared your class now is using Fields. If you want to access the fields trough reflection you should use Type.GetFields() (see Types.GetFields Method1)
I don't now which version of C# you're using but the property syntax has changed in C# 2 to the following:
public class Foo
{
public string MyField;
public string MyProperty {get;set;}
}
Wouldn't this help in reducing the amount of code?
I see this thread is already four years old, but none the less I was unsatisfied with the answers provided. OP should note that OP is referring to Fields not Properties. To dynamically reset all fields (expansion proof) try:
/**
* method to iterate through Vehicle class fields (dynamic..)
* resets each field to null
**/
public void reset(){
try{
Type myType = this.GetType(); //get the type handle of a specified class
FieldInfo[] myfield = myType.GetFields(); //get the fields of the specified class
for (int pointer = 0; pointer < myfield.Length ; pointer++){
myfield[pointer].SetValue(this, null); //takes field from this instance and fills it with null
}
}
catch(Exception e){
Debug.Log (e.Message); //prints error message to terminal
}
}
Note that GetFields() only has access to public fields for obvious reasons.
As mentioned, these are fields not properties. The property syntax would be:
public class DocumentA {
public string AgencyNumber { get; set; }
public bool Description { get; set; }
public bool Establishment { get; set;}
}