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
Related
I'm in search of a simple way to test that a collection contains logically equivalent object (ignoring instance) in c#.
public class BarObject
{
public string name { get; set; }
public string info { get; set; }
}
public class Foo
{
public Foo() { }
public IEnumerable<BarObject> Bars { get; set; } =
new List<BarObject>()
{
new BarObject() { name = "johndoe", info = "wierdo" }
};
}
[TestClass]
public class FooTests
{
[TestMethod]
public void TestDefaultInList()
{
Foo foo = new Foo();
//Using NUnit
CollectionAssert.Contains(foo.Bars.ToList(),
new BarObject() { name = "johndoe", info = "wierdo" }
);
}
}
The issue that I believe that I am having is that it is checking the instance of the object instead of the values within. How do I test that there is an object with specific values in an array simply without writing my own comparers?
What would be the best approach for having a class with two distinct fields (with distinct types) but same PropertyName.
It will always be the case that whenever one of the fields has a value, the other one will be null. I know I could create
two different classes, each of them with only one field. Is there a better alternative than creating two different classes?
Here's an example of what I'm trying to accomplish:
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class Foo
{
private Foo(int x, bool asAList = false)
{
if (asAList)
{
Baz = new List<int> { x };
}
else
{
Bar = x;
}
}
public static JObject Get(int x, bool asAList = false)
{
Foo foo = new Foo(x, asAList);
return JObject.FromObject(foo);
}
[JsonProperty(PropertyName = "qwerty", NullValueHandling = NullValueHandling.Ignore)]
public int? Bar { get; set; } = null;
[JsonProperty(PropertyName = "qwerty", NullValueHandling = NullValueHandling.Ignore)]
public List<int> Baz { get; set; } = null;
}
And I'd like to be able to do this:
JObject a = Foo.Get(1);
JObject b = Foo.Get(2, true);
You could have one private JToken JsonProperty that is being used for serializing/deserializing to either of the two public facing properties. On a set operation, that would then determine based on the JToken type if it's a JArray or not and then based on that determine which of the other properties to set. On a get operation, it would use the property that isn't null and convert that to the JToken. In order to deserialize you'll want a constructor that can be used the [JsonConstructor] can be added. Since you don't want to serialize/deserialize the other properties directly, the [JsonProperty] attribute can be removed because of the MemberSerialization.OptIn.
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class Foo
{
[JsonConstructor]
private Foo()
{ }
private Foo(int x, bool asAList = false)
{
if (asAList)
Baz = new List<int> { x };
else
Bar = x;
}
public static JObject Get(int x, bool asAList = false)
{
Foo foo = new Foo(x, asAList);
return JObject.FromObject(foo);
}
[JsonProperty(PropertyName = "qwerty", NullValueHandling = NullValueHandling.Ignore)]
private JToken Qwerty
{
get
{
return Bar.HasValue ? JToken.FromObject(Bar) : Baz != null ? JToken.FromObject(Baz) : null;
}
set
{
if (value != null && value.Type == JTokenType.Array)
Baz = value?.ToObject<List<int>>();
else
Bar = value?.ToObject<int?>();
}
}
public int? Bar { get; set; }
public List<int> Baz { get; set; }
}
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;
}
Main class:
public class Main
{
private string param;
public Main(string param) { this.param = param; }
public List<Foo> Foos
{
get {return GetFoos();}
// add functionality of saving Foo (single item, not the whole list) here?
}
private List<Foo> GetFoos()
{
List<Foo> x = new List<Foo>();
return x;
}
public class Foo
{
public int Id { get; set; }
public string Name { get; set; }
// or maybe here?
}
}
Test class:
public class Test
{
public Test()
{
var main = new Main("hi!");
// usage 1
main.Foos.Find(p => p.Id == 1).Save(); // method visible here
var foo = new Main.Foo();
// usage 2
foo.Save(); // method not visible here
}
}
Comments in the code basically say everything:
1. I want to implement the Save() method of the object Foo.
2. Method can be called only if the Foo object is picked up from the list (usage 1).
3. Method can not be called from the Foo object created alone (usage 2).
4. Method must use private value of the property param passed during initialization of the main class.
You can use an interface to hide the method Save.
To do this, the Save method must be implemented explicitly.
Additionally you need a link to the main object. In your subclass Foo you can access the private attribute from Main directly.
Interface:
public interface IFoo
{
int Id { get; set; }
string Name { get; set; }
void Save();
}
Class:
public class Main
{
private string param;
private List<IFoo> foos = new List<IFoo>();
public Main(string param) { this.param = param; }
public List<IFoo> Foos
{
get { return this.foos; }
}
public void AddFoo(int pnId, string pnName)
{
this.foos.Add(new Foo(this) { Id = pnId, Name = pnName });
}
public class Foo : IFoo
{
private Main moParent;
public Foo() { }
public Foo(Main poParent)
{
this.moParent = poParent;
}
public int Id { get; set; }
public string Name { get; set; }
//Implement interface explicitly
void IFoo.Save()
{
if (this.moParent == null)
throw new InvalidOperationException("Parent not set");
Console.WriteLine($"Save with Param: {this.moParent.param}, Id: {this.Id} Name: {this.Name}");
//Save Item
}
}
}
Usage:
var main = new Main("hi!");
main.AddFoo(1, "Foo1");
// usage 1
main.Foos.Find(p => p.Id == 1).Save(); // method visible here
var foo = new Main.Foo();
// usage 2
//foo.Save(); // Save is not visible here
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;
}
}