I have the following class example here:
public class Foo
{
public int Id { get; set; }
public string Bar { get; set; }
public string FooBar { get; set; }
public string Fizz { get; set; }
public string Buzz { get; set; }
public static Foo Create(int id, string property, string value)
{
return new Foo
{
Id = id,
};
}
}
Now, however, i want to set for example only Bar to a value in the Create method of the class if the propertyname is Bar . So i took a look at C# setting/getting the class properties by string name but i can't get this to work in the create method. Same goes for Setting a property by reflection with a string value so i'm kinda lost here.
As a small bit of clarification. I can get the above methods to work in the create, however not in the return which is where it needs to work.
The solution below seems to work for us for now, however, i think it could be optimized.
public class Foo
{
public int Id { get; set; }
public string Bar { get; set; }
public string FooBar { get; set; }
public string Fizz { get; set; }
public string Buzz { get; set; }
public static Foo Create(int id, string property, string value)
{
return new Foo
{
WebshopCustomerId = webshopCustomerId,
Bar = (typeof(Foo)).GetProperty(property).Name == "Bar" ? value : null,
FooBar = (typeof(Foo)).GetProperty(property).Name == "FooBar" ? value : null,
Fizz = (typeof(Foo)).GetProperty(property).Name == "Fizz" ? value : null,
Buzz = (typeof(Foo)).GetProperty(property).Name == "Buzz" ? value : null,
};
}
}
You can avoid reflection and keep everything simpler using a dictionary of Actions:
public class Foo
{
public int Id { get; set; }
public string Bar { get; set; }
public string FooBar { get; set; }
public string Fizz { get; set; }
public string Buzz { get; set; }
private static Dictionary<string, Action<Foo, string>> _propertySetters =
new Dictionary<string, Action<Foo, string>>()
{
{ "Bar", (foo, value) => foo.Bar = value },
{ "FooBar", (foo, value) => foo.FooBar = value },
{ "Fizz", (foo, value) => foo.Fizz = value },
{ "Buzz", (foo, value) => foo.Buzz = value },
};
public static Foo CreateWithProperty(int id, string property, string value)
{
if (String.IsNullOrEmpty(property) || !_propertySetters.ContainsKey(property))
throw new ArgumentException("property");
var instance = new Foo { Id = id };
var setter = _propertySetters[property];
setter(instance, value);
return instance;
}
}
With this approach, you can even change the property names, while keeping the configuration values the same. Depending upon the situation, it could be a huge advantage.
Having said this, I feel that your requirement could probably be better answered with more context information and a slightly different design. YMMV.
public static Foo Create(int id, string property, string value)
{
Foo ret = new Foo
{
Id = id
};
foreach (FieldInfo element in typeof(Foo).GetFields())
if (element.Name == property)
element.SetValue(ret, value);
foreach (PropertyInfo element in typeof(Foo).GetProperties())
if (element.Name == property)
element.SetValue(ret, value);
return ret;
}
Something looking like this should work for you, you could also use
ret.GetType().GetProperty(property).SetValue(ret, value);
ret.GetType().GetField(property).SetValue(ret, value);
But you'll have to handle errors.
It will work for you, but you still need to check if property is a valid property.
public static Foo Create(int id, string property, string value)
{
Foo foo = new Foo() { Id = id };
PropertyInfo propertyInfo = foo.GetType().GetProperty(property);
propertyInfo.SetValue(foo, Convert.ChangeType(value, propertyInfo.PropertyType), null);
return foo;
}
Related
I'm creating a component for Blazor and facing an issue when I have to create at runtime an object and I want to copy most of the properties, basically to clone an object but without same properties.
For example, the class Checkbox has a property called Choices.
public class Checkbox : ElementBase, IElement {
public virtual List<object>? Choices { get; set; }
}
This property stores string or CheckboxChoice.
public class CheckboxChoice
{
public string? Label { get; set; }
public string? VisibleIf { get; set; }
}
So, at runtime I have to create a new instance of an object (for example Checkbox) to display the component I want. To create an instance, I use this code (el is an implementation of IElement)
var newInstance = el.GetType();
var instance = Activator.CreateInstance(newInstance) as IElement;
Now, I have to copy some of the property's values from el to the instance. In order to copy all the properties I want, I use this extension
public static class ElementExtensions
{
public static T CopyTo<T, S>(this T target, S source, string[] propertyNames)
{
if (source == null)
return target;
Type sourceType = typeof(S);
Type targetType = typeof(T);
BindingFlags flags = BindingFlags.IgnoreCase | BindingFlags.Public |
BindingFlags.Instance;
PropertyInfo[] properties = sourceType.GetProperties();
foreach (PropertyInfo sPI in properties)
{
if (!propertyNames.Contains(sPI.Name))
{
PropertyInfo tPI = targetType.GetProperty(sPI.Name, flags);
if (tPI != null && tPI.CanWrite &&
tPI.PropertyType.IsAssignableFrom(sPI.PropertyType))
{
tPI.SetValue(target, sPI.GetValue(source, null), null);
}
}
}
return target;
}
}
The problem with this extension is that it is not copying the property Choices or other property that are not a primitive type.
I don't want to use AutoMapper because I like to have a light component without dependencies, apart from .NET6. How can I change the function to copy also the complex properties?
Update
This is the code I use. ElementData has the list of components (like Checkbox and Textbox) to display.
public List<IElement>? RepeaterElements { get; set; }
foreach (var el in ElementData)
{
var newInstance = el.GetType();
var instance = Activator.CreateInstance(newElement, null);
instance.CopyTo(data, new[] { "Parent", "Index", "QuestionNumber", "Name" });
instance.Parent = parentName;
instance.Index = row;
instance.QuestionNumber = question;
instance.Name = instance.GetElementName();
RepeaterElements.Add(new RepeaterElement() { Element = instance, Row = row });
}
I've always defaulted to using serialization to handle deep object copies.
Here is an example:
using static Newtonsoft.Json.JsonConvert;
var instanceOfMyClass = new MyClass()
{
Id = 1,
Name = "John Doe",
Age = 21
};
Console.WriteLine(SerializeObject(instanceOfMyClass));
var copyOfMyClass = DeserializeObject<MyClass>(SerializeObject(new { instanceOfMyClass.Name, instanceOfMyClass.Age }));
Console.WriteLine(SerializeObject(copyOfMyClass));
public class MyClass
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
It's a simple and performant pattern on small classes.
EDIT:
Can also be done between classes if the Property names are the same:
sing static Newtonsoft.Json.JsonConvert;
var instanceOfMyClass = new MyClass()
{
Id = 1,
Name = "John Doe",
Age = 21
};
Console.WriteLine(SerializeObject(instanceOfMyClass));
var copyOfMyClass = DeserializeObject<MySecondClass>(SerializeObject(new { instanceOfMyClass.Name, instanceOfMyClass.Age }));
Console.WriteLine(SerializeObject(copyOfMyClass));
public class MyClass
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
public class MySecondClass
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
Does anybody know how to convert Google.Cloud.BigQuery.V2.BigQueryResults to a custom type? As far as I see the BigQueryClient type doesn't have generic versions of ExecuteQuery and ExecuteQueryAsync.
According to Google BigQuery quickstart guide we can do something like that:
public class Foo
{
public string FirstValue { get; set; }
public string SecondValue { get; set; }
public string ThirdValue { get; set; }
}
public IEnumerable<Foo> GetQueryResult()
{
var queryExecutionResult = client.ExecuteQuery(Query, null);
foreach (var row in queryExecutionResult)
{
yield return new Foo
{
FirstValue = row["column1"],
SecondValue = row["column2"],
ThirdValue = row["column3"]
};
}
}
I have implemented my custom converter which uses reflection under the hood. I don't quite like a reflection. So perhaps somebody knows some better way. I put my implementation below.
public class Foo
{
// I use custom attribute which is similar to DescriptionAttribute.
[BigQueryColumnName("column1")]
public string FirstValue { get; set; }
[BigQueryColumnName("column2")]
public string SecondValue { get; set; }
[BigQueryColumnName("column3")]
public string ThirdValue { get; set; }
}
public IEnumerable<Foo> GetQueryResult()
{
var queryExecutionResult = client.ExecuteQuery(Query, null);
return queryExecutionResult.Select(bigQueryRowToFooConverter.ConvertToFoo);
}
public Foo ConvertToFoo(BigQueryRow row)
{
var item = new Foo();
foreach (var propertyInfo in typeof(Foo).GetProperties())
{
var attribute = (BigQueryColumnNameAttribute)Attribute.GetCustomAttribute(propertyInfo, typeof(BigQueryColumnNameAttribute));
var value = row[attribute.ColumnName];
propertyInfo.SetValue(item, value);
}
return item;
}
How can I access the custom attribute of the parent or owner object.
Look at the FieldInfo property of the SQLFieldInfo struct
Here's a more detailed program that will compile and run that shows what I need.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Employee myclass = new Employee();
// Load from sql server...
myclass.Name = "Alain";
myclass.Age = 51;
//----
MessageBox.Show(myclass.Name.ToString()); // Should return Alain
MessageBox.Show(myclass.Age.FieldInfo.Type.ToString()); // Should output "int"
}
}
// This next class is generated by a helper exe that reads SQL table design and create the class from it
[SQLTableAttribute(DatabaseName = "Employees", Schema = "dbo", TableName = "Employees")]
public class Employee
{
[SQLFieldAttribute(FieldName = "ID", Type = SqlDbType.Int)]
public SQLFieldInfo<int> ID { get; set; }
[SQLFieldAttribute(FieldName = "Name", Type = SqlDbType.NVarChar, Size = 200)]
public SQLFieldInfo<String> Name { get; set; }
[SQLFieldAttribute(FieldName = "Age", Type = SqlDbType.Int)]
public SQLFieldInfo<int> Age { get; set; }
}
public struct SQLFieldInfo<T>
{
private readonly T value;
public SQLFieldInfo(T Value)
{
this.value = Value;
}
public static implicit operator SQLFieldInfo<T>(T Value)
{
return new SQLFieldInfo<T>(Value);
}
public T Value
{
get
{
return this.value;
}
}
public override string ToString()
{
return this.value.ToString();
}
public SQLFieldAttribute FieldInfo
{
get
{
// Need to retreive the attribute class of the parent or declaring member
return null;
}
}
}
// Holds the sql field information
public class SQLFieldAttribute : Attribute
{
public string FieldName { get; set; }
public SqlDbType Type { get; set; }
public bool AllowNull { get; set; }
public int Size { get; set; }
}
// Holds the sql table information
public class SQLTableAttribute : Attribute
{
public string DatabaseName { get; set; }
public string Schema { get; set; } = "dbo";
public string TableName { get; set; }
}
Thank you!
Alain
My data class is as follows (should be fairly translatable to A above):
public class Foo
{
[Argument(Help = "Name", AssignmentDelimiter = "=")]
public string Name
{
get;
set;
}
}
A helper class is responsible of reading attribute values of objects:
static public string GetCommandLineDelimiter<T>(Expression<Func<T>> property)
{
if(property != null)
{
var memberExpression = (MemberExpression)property.Body;
string propertyName = memberExpression.Member.Name;
PropertyInfo prop = typeof(Arguments).GetProperty(propertyName);
if(prop != null)
{
object[] dbFieldAtts = prop.GetCustomAttributes(typeof(ArgumentAttribute), true);
if(dbFieldAtts.Length > 0)
{
return ((ArgumentAttribute)dbFieldAtts[0]).AssignmentDelimiter;
}
}
}
return null;
}
To use it, simply:
string delimiter = GetCommandLineDelimiter(() => myObject.Name);
That will get the attribute value of AssignmentDelimiter on property Name, i.e. "=".
First, MSDN is your friend.
Then, if you want to get the attributes for ancestors just specify true in the inherit flag of the method:
var attribute = typeof(A).GetProperty("myprop").GetCustomAttributes(true)
.OfType<MycustomAttrib>().FirstOrDefault();
This works. I am doing a lazy initialization of a reference to the custom attribute by using reflection to look at all the properties of all the types.
public class MycustomAttribAttribute : Attribute
{
public MycustomAttribAttribute(string name)
{
this.Name=name;
}
public string Name { get; private set; }
}
class A
{
public A() { MyProp=new B(); }
[MycustomAttrib(name: "OK")]
public B MyProp { get; set; }
}
class B
{
private static Lazy<MycustomAttribAttribute> att = new Lazy<MycustomAttribAttribute>(() =>
{
var types = System.Reflection.Assembly.GetExecutingAssembly().DefinedTypes;
foreach(var item in types)
{
foreach(var prop in item.DeclaredProperties)
{
var attr = prop.GetCustomAttributes(typeof(MycustomAttribAttribute), false);
if(attr.Length>0)
{
return attr[0] as MycustomAttribAttribute;
}
}
}
return null;
});
public string MyProp2
{
get
{
return att.Value.Name;
}
}
}
class Program
{
static void Main(string[] args)
{
// Finds the attribute reference and returns "OK"
string name = (new A()).MyProp.MyProp2;
// Uses the stored attribute reference to return "OK"
string name2 = (new A()).MyProp.MyProp2;
}
}
I want to access a class member by binding, but without any UI nor XAML code.
class Foo {
public int Value { get; set; }
}
class Bar {
public Foo foo { get; set; }
}
Bar bar = new Bar() {
foo = new Foo() {
Value = 2
}
}
Binding b = new System.Windows.Data.Binding("foo.Value");
b.Source = bar;
// Now I want a method which returns bar.foo.Value, would be like that:
int value = b.GET_VALUE(); // this method would return 2
Is there such a method ?
I found the answer, thanks to:
How to get class members values having string of their names?
No need of Binding class:
public static class Extensions
{
public static object GetPropertyValue(this object Obj, string PropertyName)
{
object Value = Obj;
foreach (string Property in PropertyName.Split('.'))
{
if (Value == null)
break;
Value = Value.GetType().GetProperty(Property).GetValue(Value, null);
}
return Value;
}
}
Usage:
class Foo {
public int Value { get; set; }
}
class Bar {
public Foo foo { get; set; }
}
Bar bar = new Bar() {
foo = new Foo() {
Value = 2
}
}
bar.GetPropertyValue("foo.Value"); // 2
bar.foo = null;
bar.GetPropertyValue("foo.Value"); // null
I want to make a generic search UserControl in wpf. I want it to get a collection of objects and a name of a property to search by.
The problem is I can't use generics because the code that calls the search function also can't know of the type.
Is there a way to achieve this? Or some way to query an Object that is underneath another type?
Consider this example.
interface IFoo
{
}
class Bar1 : IFoo
{
//interface implementations
public string Property1 { get; set; }
public string myProperty1 { set; get; }
}
class Bar2 : IFoo
{
//interface implementations
public string Property1 { get; set; }
public string myProperty1 { set; get; }
}
//Search the list of objects and access the original values.
List<IFoo> foos = new List<IFoo>();
foos.Add(new Bar1
{
Property1 = "bar1",
myProperty1 ="myBar1"
});
foos.Add(new Bar1());
foos.Add(new Bar2());
foos.Add(new Bar2());
//Get the objects.
foreach (var foo in foos)
{
//you can access foo directly without knowing the original class.
var fooProperty = foo.Property1;
//you have to use reflection to get the original type and its properties and methods
Type type = foo.GetType();
foreach (var propertyInfo in type.GetProperties())
{
var propName = propertyInfo.Name;
var propValue = propertyInfo.GetValue(foo);
}
}
var result = list.Where(a => a.propertyName);
You can use reflection
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
var Data = new List<object>() { new A() { MyProperty = "abc" }, new B() { MyProperty = "cde"} };
var Result = Data.Where(d => (d.GetType().GetProperty("MyProperty").GetValue(d) as string).Equals("abc"));
// Result is IEnumerable<object> wich contains one A class object ;)
}
}
class A
{
public string MyProperty { get; set; }
}
class B
{
public string MyProperty { get; set; }
}
}