C# PropertyInfo (Generic) - c#

Lets say i have this class:
class Test123<T> where T : struct
{
public Nullable<T> Test {get;set;}
}
and this class
class Test321
{
public Test123<int> Test {get;set;}
}
So to the problem lets say i want to create a Test321 via reflection and set "Test" with a value how do i get the generic type?

Since you are starting from Test321, the easiest way to get the type is from the property:
Type type = typeof(Test321);
object obj1 = Activator.CreateInstance(type);
PropertyInfo prop1 = type.GetProperty("Test");
object obj2 = Activator.CreateInstance(prop1.PropertyType);
PropertyInfo prop2 = prop1.PropertyType.GetProperty("Test");
prop2.SetValue(obj2, 123, null);
prop1.SetValue(obj1, obj2, null);
Or do you mean you want to find the T?
Type t = prop1.PropertyType.GetGenericArguments()[0];

This should do it more or less. I have no access to Visual Studio right now, but it might give you some clue how to instantiate the generic type and set the property.
// Define the generic type.
var generic = typeof(Test123<>);
// Specify the type used by the generic type.
var specific = generic.MakeGenericType(new Type[] { typeof(int)});
// Create the final type (Test123<int>)
var instance = Activator.CreateInstance(specific, true);
And to set the value:
// Get the property info of the property to set.
PropertyInfo property = instance.GetType().GetProperty("Test");
// Set the value on the instance.
property.SetValue(instance, 1 /* The value to set */, null)

Try something like this:
using System;
using System.Reflection;
namespace test {
class Test123<T>
where T : struct {
public Nullable<T> Test { get; set; }
}
class Test321 {
public Test123<int> Test { get; set; }
}
class Program {
public static void Main() {
Type test123Type = typeof(Test123<>);
Type test123Type_int = test123Type.MakeGenericType(typeof(int));
object test123_int = Activator.CreateInstance(test123Type_int);
object test321 = Activator.CreateInstance(typeof(Test321));
PropertyInfo test_prop = test321.GetType().GetProperty("Test");
test_prop.GetSetMethod().Invoke(test321, new object[] { test123_int });
}
}
}
Check this Overview of Reflection and Generics on msdn.

Related

How to cast PropertyInfo to its own type using reflection

I am trying to use reflection for getting the property name declared and its value, I am able to get the declared property name using property info the main concern I am having is I want to get the value for the property and I don't know the object type so I cant cast directly.
I know we need to use item.GetValue(object) but here the object, I need to pass using reflection.
For example, if you see the below code
Class structure
public abstract class ObjectInputs{}
public class ValveInputs : ObjectInputs
{
public Conditions Conditions { get; set; } = new Conditions();
}
public class Conditions :IExportable
{
[CanExportAttribute]
public string north {get;set;}
}
Method
public void Append(Scenario scenario)
{
var scenarioInputs = (commonDomain.ObjectInputs)scenario.Inputs; // ObjectInputs is an abstract class
var exportableInputs = scenarioInputs.GetType().GetProperties().Where(x =\> typeof(IExportable).IsAssignableFrom(x.PropertyType)); // I extraced property having interface IExportable
var listOfExportableProperties = new ScenarioExtract();
foreach (var exportableInput in exportableInputs)
{
var allProperties = ((System.Reflection.TypeInfo)exportableInput.PropertyType).DeclaredProperties; // Got all the property details
var propertyHavingAttribute = allProperties.Where(x =\> x.CustomAttributes.Where(z =\> z.AttributeType == typeof(CanExportAttribute)).Any()).ToArray(); // Got the properties which i need to extract.
The issue is here, if i do this then its creating a new instance and the values of each properties are set to default. I want to cast the exportableInput to its type (I cant hard code the type casting) so that i can use the value below.
object destination = Activator.CreateInstance(scenarioInputs.GetType());
foreach (var item in propertyHavingAttribute)
{
var detail = new InputPropertyDetail { InputName = item.Name, InputValue = \*\*item.GetValue(destination).ToString() \*\*}; \*\*want to use value here\*\*
listOfExportableProperties.PropertyDetails.Add(detail);
}
}
spreadsheetBuilder.AppendComponenet(listOfExportableProperties);
}
If you're using Activator.CreateInstance, it will always create a new instance (as the name inplies) with default values. Instead you must use the value of the exportableInput property.
object destination = exportableInput.GetValue(scenarioInputs);
Then you can get the actual value of the exportable property of the instance with InputValue = item.GetValue(destination).ToString().

C# Dynamically assign a specific default value to all fields of a certain type in new object instances?

I have a class that contains multiple string fields. Whenever an object of this class is instantiated, I'd like those fields to be automatically assigned with the same specific default value (something like "Undefined"). The reason is:
If I have to serialize the object before all fields are populated with real data, I want those fields to display as this default value rather than being null or string.Empty.
String fields may be added/removed from this class as the project progresses. I'd like to not have to touch the constructor every time that occurs.
Is there any way to do this other than explicitly assigning the default value to each of the string fields one by one in the class constructor?
In C# 6.0 and above, you can use Auto-Property Initializer:
https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-6#auto-property-initializers
Basically:
public string Property { get; set; } = "UNDEFINED";
You would have to use reflection. Something like this
Type type = obj.GetType();
PropertyInfo[] properties = type.GetProperties();
foreach (PropertyInfo property in properties)
{
if (property.PropertyType == typeof(string)) property.setValue(obj, "UNDEFINED");
}
First of all: I don't see how it could be best practice to do what you want.
If you want something like this to show up in your code:
public string Property { get; set; } = "UNDEFINED";
You should probably look into creating custom snippets that simply write exactly that. e.g. https://msdn.microsoft.com/en-us/library/ms165394.aspx
If you don't want that, you could use reflection to find all fields (e.g. strings) in the constructor and set them.
C# Reflection - Get field values from a simple class
FieldInfo[] fields = data.GetType().GetFields(BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.Instance);
Setting a property by reflection with a string value
Ship ship = new Ship();
string value = "5.5";
PropertyInfo propertyInfo = ship.GetType().GetProperty("Latitude");
propertyInfo.SetValue(ship, Convert.ChangeType(value, propertyInfo.PropertyType), null);
Well, why not have an extension method like
public static class MyClass
{
public static string GetDefault(this str, string defaultVal)
{
return string.IsNullOrEmpty(str) ? defaultVal : str;
}
}
For a type
public class SomeClass
{
public string str = string.Empty;
}
You can call
SomeClass s = new SomeClass();
s.str.GetDefault("UNDEFINED");
You can initialize values to fields directly instead of in the constructor.
private string myStringVariable = "UNDEFINED";
Perhaps you should reconsider the structure of your program though if it permits many fields to be initialized to undefined.
Maybe I am misunderstanding this but why not do word for word what you described in the question in your constructor?
public class Weee
{
public string name { get; set; }
public int order { get; set; }
public string whatever { get; set; }
public Weee()
{
foreach(var p in typeof(Weee).GetProperties().Where(a => a.PropertyType == typeof(string)))
{
p.SetValue(this, "wut");
}
}
}
You can create a property initializer and have a base class use it. Your classes can then inherit from the base and have their properties automatically initialized:
public class PropertyInitializer
{
public void Initialize<T>(object obj, T value)
{
PropertyInfo[] properties = obj.GetType().GetProperties();
foreach (PropertyInfo property in properties)
{
if (property.PropertyType == typeof(T))
{
property.SetValue(obj, value);
}
}
}
}
public class InitializedBase
{
protected InitializedBase()
{
var initializer = new PropertyInitializer();
//Initialize all strings
initializer.Initialize<string>(this, "Juan");
//Initialize all integers
initializer.Initialize<int>(this, 31);
}
}
//Sample class to illustrate
public class AutoInitializedClass : InitializedBase
{
public string Name { get; set; }
public int Age { get; set; }
public override string ToString()
{
return string.Format("My name is {0} and I am {1} years old", Name, Age);
}
}
Sample usage:
AutoInitializedClass sample = new AutoInitializedClass();
Console.WriteLine(sample);
Console output:
My name is Juan and I am 31 years old
Notice the base class is using the PropertyInitializer class to initialize fields. This is a simplified example. You can expand it as it fits you (it may not work out of the box with all types).
I personally don't recommend this. It's called a constructor for a reason but you asked a question and I provided an answer.
Here is a simple class from which you can inherit that does exactly what you want:
Example usage:
public class MyClass : DefaultedObject<string>
{
public string MyStringField;
protected override string Default => "UNDEFINED";
}
var myClass = new MyClass();
// myClass.MyStringField == "UNDEFINED"
Implementation:
public abstract class DefaultedObject<T>
{
protected DefaultedObject()
{
T defaultValue = Default;
FieldInfo[] fields = GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
foreach(FieldInfo field in fields) {
if(field.FieldType == typeof(T)) {
field.SetValue(this, defaultValue);
}
}
}
protected abstract T Default { get; }
}
I appreciate all the feedback to this question. Here's what ended up working. First, for any string attributes in the class that I wanted to receive an automatic default value, I established as a property:
public string attribute1 {get; set;}
public string attribute2 {get; set;}
And so on. Then, in the class constructor, I included the following loop which iterates through each property of type string:
foreach(PropertyInfo property in GetType().GetProperties())
{
if (property.PropertyType == typeof(string))
property.SetValue(this, "UNDEFINED"));
}
This produced the desired outcome for me.

Setting C# property value when you know its class name (not property name)

I have a class as follows:
public class DummyReturnDto
{
public Set1ReturnDto Foo { get; set; }
public Set2ReturnDto Bar { get; set; }
public DummyReturnDto()
{
Set1 = new Set1ReturnDto();
Set2 = new Set2ReturnDto();
}
}
where all the properties are guaranteed to have classes as their types and will be unique. I would like to use reflection to set the value for the property given a particular type. So for Set1ReturnDto:
var propertyInfo = obj.GetType().GetProperty(Set1ReturnDto, ??????);
propertyInfo.SetValue(obj, value, null);
and then for Set2ReturnDto
var propertyInfo = obj.GetType().GetProperty(Set2ReturnDto, ??????);
propertyInfo.SetValue(obj, value, null);
EDIT:
This is part of the needed knowledge to implement requirements for Generic approach to dealing with multiple result sets from EF stored procedure
This will do it:
var propertyInfo = typeof(DummyReturnDto).GetProperties()
.Single(p => p.PropertyType == typeof(Set1ReturnDto));

Accessing C# property name or attributes

I would like to automatically generate SQL statements from a class instance. The method should look like Update(object[] Properties, object PrimaryKeyProperty). The method is part of an instance (class, base method - generic for any child). Array of properties is an array of class properties, that will be used in update statement. Property names are equal to table field names.
The problem is that I can't get property names.
Is there any option to get a property name inside class instance?
sample:
public class MyClass {
public int iMyProperty { get; set; }
public string cMyProperty2 { get; set; }
{
main() {
MyClass _main = new MyClass();
_main.iMyProperty.*PropertyName* // should return string "iMyProperty"
{
I am aware of PropertyInfo, but I don't know hot to get the ID of a property from GetProperties() array.
Any suggestion?
Just wrote an implementation of this for a presentation on lambdas for our usergroup last Tuesday.
You can do
MembersOf<Animal>.GetName(x => x.Status)
Or
var a = new Animal()
a.MemberName(x => x.Status)
the code:
public static class MembersOf<T> {
public static string GetName<R>(Expression<Func<T,R>> expr) {
var node = expr.Body as MemberExpression;
if (object.ReferenceEquals(null, node))
throw new InvalidOperationException("Expression must be of member access");
return node.Member.Name;
}
}
Link to the presentation and code samples.
Also in SVN (more likely to be updated): http://gim-projects.googlecode.com/svn/presentations/CantDanceTheLambda
I found a perfect solution in This Post
public static string GetPropertyName<T>(Expression<Func<T>> propertyExpression)
{
return (propertyExpression.Body as MemberExpression).Member.Name;
}
And then for the usage :
var propertyName = GetPropertyName(
() => myObject.AProperty); // returns "AProperty"
Works like a charm
You can do something like this:
Type t = someInstance.getType();
foreach (MemberInfo mi in t.GetMembers())
{
if (mi.MemberType == MemberTypes.Property)
{
Console.WriteLine(mi.Name);
}
}
to get all the property names for instance's type.
You can get the name (I assume that's what you meant by ID) of a property using PropertyInfo.Name. Just loop through the PropertyInfo[] returned from typeof(className).GetProperties()
foreach (PropertyInfo info in typeof(MyClass).GetProperties())
{
string name = info.Name;
// use name here
}
Since you already have an explicit handle to the specific property you want, you know the name - can you just type it?
Not 100% sure if this will get you what you're looking for, this will fetch all properties with [Column] attribute inside your class:
In the datacontext I have:
public ReadOnlyCollection<MetaDataMember> ColumnNames<TEntity>( )
{
return this.Mapping.MappingSource.GetModel(typeof(DataContext)).GetMetaType(typeof(TEntity)).DataMembers;
}
Fetching the table column-names that are properties inside the class:
MyDataContext db = GetDataContext();
var allColumnPropertyNames = db.ColumnNames<Animal>().Where(n => n.Member.GetCustomAttributes(typeof(System.Data.Linq.Mapping.ColumnAttribute), false).FirstOrDefault() != null).Select(n => n.Name);
Let's say (from the first sample, method update of a class MyClass):
public class MyClass {
public int iMyStatusProperty { get; set; }
public int iMyKey { get; set; }
public int UpdateStatusProperty(int iValue){
this.iMyStatusProperty = iValue;
return _Update( new[iMyStatusProperty ], iMyKey); // this should generate SQL: "UPDATE MyClass set iMyStatusProperty = {iMyStatusProperty} where iMyKey = {iMyKey}"
}
{iMyStatusProperty} and {iMyKey} are property values of a class instance.
So, the problem is how to get property name (reflection) from a property without using names of properties as strings (to avoid field name typos).

Using Reflection to set a Property with a type of List<CustomClass>

How can I use reflection to create a generic List with a custom class (List<CustomClass>)? I need to be able to add values and use
propertyInfo.SetValue(..., ..., ...) to store it. Would I be better off storing these List<>'s as some other data structure?
Edit:
I should have specified that the object is more like this, but Marc Gravell's answer works still.
class Foo
{
public List<string> Bar { get; set; }
}
class Foo
{
public string Bar { get; set; }
}
class Program
{
static void Main()
{
Type type = typeof(Foo); // possibly from a string
IList list = (IList) Activator.CreateInstance(
typeof(List<>).MakeGenericType(type));
object obj = Activator.CreateInstance(type);
type.GetProperty("Bar").SetValue(obj, "abc", null);
list.Add(obj);
}
}
Here's an example of taking the List<> type and turning it into List<string>.
var list = typeof(List<>).MakeGenericType(typeof(string));

Categories