What's the best way to compare 2 versions of the same object and return a list of differences (name of property, old value and new value) See object graph below for an example. What if there was a change in the Product name how would I bubble that up into a list of property differences?
static void Main(string[] args)
{
Customer c1 = new Customer();
c1.DBA = "Test1";
c1.LatestOrder.DateOrdered = new DateTime(2011, 7, 12);
c1.LatestOrder.OrderDetails.Product = "Product1";
Customer c2 = new Customer();
c2.DBA = "Test1";
c2.LatestOrder.DateOrdered = new DateTime(2011, 7, 12);
c2.LatestOrder.OrderDetails.Product = "Product2";
}
So the test above shows that everything in the 2 objects are the same except for the product name. Maybe, just as proof of concept, a list showing the property name, old value and new value.
public class Customer
{
public string DBA { get; set; }
public Order LatestOrder { get; set; }
public Customer()
{
LatestOrder = new Order();
}
}
public class Order
{
public int Id { get; set; }
public DateTime DateOrdered { get; set; }
public OrderDetails OrderDetails { get; set; }
public Order()
{
OrderDetails = new OrderDetails();
}
}
public class OrderDetails
{
public String Product { get; set; }
}
}
You could try it using reflection. Something like this:
class Difference
{
private Difference(string propertyPath, object value1, object value2)
{
PropertyPath = propertyPath;
Value1 = value1;
Value2 = value2;
}
public string PropertyPath { get; private set; }
public object Value1 { get; private set; }
public object Value2 { get; private set; }
public Difference Extend(string propertyName)
{
return new Difference(
string.Format("{0}.{1}", propertyName, PropertyPath), Value1, Value2);
}
public override string ToString()
{
return string.Format("{0}: {1}, {2}", PropertyPath, Value1, Value2);
}
public static IEnumerable<Difference> GetDifferences<T>(T value1, T value2)
{
return GetDifferences(typeof(T), value1, value2);
}
// types in this collection are compared directly
// and not recursively using their properties
private static readonly Type[] PrimitiveTypes =
new[] { typeof(int), typeof(string), typeof(DateTime) };
public static IEnumerable<Difference> GetDifferences(
Type type, object obj1, object obj2)
{
foreach (var property in
type.GetProperties(BindingFlags.Instance | BindingFlags.Public))
{
var val1 = property.GetValue(obj1, null);
var val2 = property.GetValue(obj2, null);
if (PrimitiveTypes.Contains(property.PropertyType))
{
if (!val1.Equals(val2))
yield return new Difference(property.Name, val1, val2);
}
else
{
foreach (var difference in
GetDifferences(property.PropertyType, val1, val2))
yield return difference.Extend(property.Name);
}
}
}
}
This recursively walks the object graph and returns something like
LatestOrder.DateOrdered: 12.7.2011 0:00:00, 11.7.2011 0:00:00
LatestOrder.OrderDetails.Product: Product1, Product2
Doing this is quite fragile, though. For example, it could easily cause stack overflow if you have any kind of cyclic relations. (For example, DateTime does, in the form of the Date property, so I had to include it in primitive types.) And if you have some property that depends on other properties, one actual difference may be reported multiple times. (If DateTime wasn't cyclic, this would happen there: two DateTimes that differ in the Seconds property also differ in TotalSeconds, TotalMinutes, etc.)
this may help you get started, essentially if you know obj1 and obj2 are of the same type, you get all of the public properties and compare them one by one... you may want to handle collections differently though (comparing each item in the collection)...
you could then compile all this info in some dictionary or custom object.
foreach (var info in obj1.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public))
{
var val1 = info.GetValue(obj1, null);
var val2 = info.GetValue(obj2, null);
// check if val1 == val2
}
You could do something similar to the Comparable class, but with a list of differences instead of an integer. For example
public class ClassName {
...
ArrayList compareTo(ClassName other) {
if (this.attribute.equals(other.attribute)) {
add to list
}
}
}
If the old version and the new version are in the same object instance, maybe you can use a variant of the Memento Pattern (http://en.wikipedia.org/wiki/Memento_pattern).
If you are thinking to create a reusable component, you should think about the use of reflection classes. With reflection you can view all the properties values, even if you don't know all the properties names.
Related
How to serialize a generic(T) object which can hold any type of data (int / string / DateTime) using Protobuf-net. Following is my code
[ProtoContract]
public class E1DataRow
{
[ProtoMember(1)]
public List<NameValue> NameValues { get; set; }
public E1DataRow()
{
NameValues = new List<NameValue>();
}
public void AddNameValue(string name, object obj, Type type)
{
NameValues.Add(new NameValue { Name = name, Value = obj, ValueType = type });
}
}
[ProtoContract]
public class NameValue
{
[ProtoMember(1)]
public string Name { get; set; }
[ProtoMember(2)]
public object Value { get; set; }
[ProtoMember(3)]
public Type ValueType { get; set; }
}
serialization code
var e1DataRows = new List<E1DataRow>();
/*
Code to add Data rows to e1DataRows
e1DataRow.AddNameValue(column.ColumnName, value, column.TypeOfColumn);
*/
using (var stream = File.OpenWrite(path))
{
Serializer.Serialize(stream, e1DataRows);
}
[ProtoMember(2, DynamicType = true)]
public object Value { get; set; }
Above code throws following error (DynamicType = true)
ProtoMemberAttribute.DynamicType' is obsolete: 'Reference-tracking and dynamic-type are not currently implemented in this build; they may be reinstated later; this is partly due to doubts over whether the features are adviseable, and partly over confidence in testing all the scenarios (it takes time; that time hasn't get happened); feedback is invited'
It would be great if you can help with how to serialize a List using Protobug-net. Thanks...
You may want to look at https://github.com/dotarj/protobuf-net-data - this isn't affiliated with protobuf-net (different authors etc), but it uses protobuf-net to perform serialization of DataTable and data-readers, so it might do what you want ready-made.
As for implementing it yourself:
protobuf-net does not support object (or dynamic, which is just a fancy way of spelling object), fundamentally. There are ways of working around this, essentially similar to the oneof handling in protobuf - i.e. something like (in protobuf terms):
message Foo {
oneof payload {
string payload_string = 1;
bool payload_bool = 2;
int32 payload_int32 = 3;
float payload_float = 4;
// etc
}
}
This is pretty easy to put together in protobuf-net thanks to "conditional serialization", which means you could do something like:
public object Value { get; set; }
[ProtoMember(1)]
public string ValueString
{
get => (string)Value;
set => Value = value;
}
public bool ShouldSerializeValueString()
=> Value is string;
[ProtoMember(2)]
public string ValueBoolean
{
get => (bool)Value;
set => Value = value;
}
public bool ShouldSerializeValueBoolean()
=> Value is string;
// etc
If on c# >= 4 you might want to try the following:
[ProtoContract]
public class E1DataRow
{
[ProtoMember(1)]
public List<NameValue<dynamic>> NameValues { get; set; }
public E1DataRow()
{
NameValues = new List<NameValue<dynamic>>();
}
public void AddNameValue(string name, dynamic obj)
{
NameValues.Add(new NameValue<dynamic> { Name = name, Value = obj });
}
}
public class NameValue<T>
{
[ProtoMember(1)]
public string Name { get; set; }
[ProtoMember(2)]
public T Value { get; set; }
[ProtoMember(3)]
public Type ValueType { get { return Value.GetType(); } }
}
Not sure if Protobuf-net likes the List<NameValue<dynamic>>, can't test it as of now.
ProtoMember(3) at ValueType possibly is not necessary as of being readonly anyways.
Is it possible to add a log to the destination object, when using AutoMapper?
If I have two objects:
class A
{
int PropertyOne
int PropertyTwo
int PropertyThree
List<string> Log
}
class B
{
int PropertyOne
int PropertyTwo
}
When mapping from B to A, I'd like to automatically have a log entry added to A.Log for every property that is changed.
E.g. if during a mapping operation, PropertyOne = 3 on both objects, but A.PropertyTwo = 1 and B.PropertyTwo = 2, I'd like to have a log entry added to A.Log - preferably something like "PropertyTwo changed from 1 to 2"
Instead of an auto-property, create a property with a custom setter in which you add an entry to the log list.
Example console application:
public static class Program
{
public class A
{
private int _PropertyOne;
private int _PropertyTwo;
private int _PropertyThree;
public int PropertyOne
{
get { return _PropertyOne; }
set
{
if (value == _PropertyOne)
return;
Log.Add(string.Format("PropertyOne changing value from {0} to {1}", _PropertyOne, value));
_PropertyOne = value;
}
}
public int PropertyTwo
{
get { return _PropertyTwo; }
set
{
if (value == _PropertyTwo)
return;
Log.Add(string.Format("PropertyOne changing value from {0} to {1}", _PropertyTwo, value));
_PropertyTwo = value;
}
}
public int PropertyThree
{
get { return _PropertyThree; }
set
{
if (value == _PropertyThree)
return;
Log.Add(string.Format("PropertyOne changing value from {0} to {1}", _PropertyThree, value));
_PropertyThree = value;
}
}
public List<string> Log { get; private set; }
public A()
{
Log = new List<string>();
}
}
public class B
{
public int PropertyOne { get; set; }
public int PropertyTwo { get; set; }
}
public static void Main(string[] args)
{
AutoMapper.Mapper.Initialize(cfg =>
{
cfg.CreateMap<A, B>().ReverseMap();
});
var b = new B() {PropertyOne = 1, PropertyTwo = 2};
var a = AutoMapper.Mapper.Map<B, A>(b);
a.Log.ForEach(s => Console.WriteLine(s));
}
}
This will output:
PropertyOne changing value from 0 to 1
PropertyTwo changing value from 0 to 2
You could implement a custom type converter that would work with a marker interface called IPropertyLogger. Any subtype of that could be explicitly used by AutoMapper.
The type converter could use reflection and perform the diff-like operation you are requesting before calling default AutoMapper behavior. This would work for all tagged types and you would not have to code each object specifically for the case.
Your reflection based diff code would handle all of the logging you require keeping you objects clean from implementation code.
I have a class named Myclass with an override of ToString() like this:
class Field
{
}
class MyClass
{
Field propretie1
Field propretie2
.
.
.
Field propretie15
public override string ToString()
{
StringBuilder temp = new StringBuilder();
temp.Append(propretie1.ToString())
temp.Append("|");
temp.Append(propretie2.ToString())
temp.Append("|");
.
.
temp.Append(propretie15.ToString())
return temp.ToString();
}
}
I'd like to know if there is a better way to get over all the properties of Myclass with the declaration order to implement the ToString function.
No, there is no way to do this by your requirements other than coding each function manually. It would be easy with reflection, but
The GetFields method does not return fields in a particular order, such as alphabetical or declaration order. Your code must not depend on the order in which fields are returned, because that order varies.
So there is no way to actually get the order of the declaration. You could try alphabetical order by ordering them yourself though.
var allProps = typeof(MyClass).GetProperties(); // or GetFields() if they are fields
Array.Sort(allProps, (x, y) => x.Name.CompareTo(y.Name));
return string.Join("|", allProps.Select(x => x.GetValue(this)));
This uses Linq Select and an overload of GetValue from .NET 4.5 (Visual Studio 2012).
.Net offers an XmlSerializer object aimed at giving you a representation of your object.
You can take advantage of that, just grabbing text nodes and joining them:
public override string ToString()
{
return this.Stringify(); //calls reusable code to "stringify" any object
}
//converts an object's properties to a string of pipe delimited values
public static string Stringify<T>(this T obj)
{
var xs = new XmlSerializer(obj.GetType());
var doc = new XDocument();
using (var writer = doc.CreateWriter())
{
xs.Serialize(writer, obj);
}
var s = from text in doc.XPathSelectElements("//*[./text()]") select text.Value;
return string.Join("|", s);
}
Calling ToString on properties which are complex classes is more complex... to do that use the XmlElement attribute on those properties so the serializer knows you want to output these properties, then allow implicit conversion to string so the serializer doesn't error. Weirdly you also need to implement implicit conversion from string too (I guess because the serializer has the ability to deserialize too); but that doesn't have to work. Very hacky.
An alternate is to make your child type serializable using the [Serializable] attribute, put [XmlIgnore] on any public properties, then create a property with a get method calling to ToString function, and a dummy set method (again to trick the serializer). Not great, but it works.
Working Example
using System;
using System.Linq;
using System.Xml.Linq;
using System.Xml.Serialization;
using System.Xml.XPath;
namespace StackOverflow
{
public static class ObjectStringer
{
public static string Stringify<T>(this T obj)
{
var xs = new XmlSerializer(obj.GetType());
var doc = new XDocument();
using (var writer = doc.CreateWriter())
{
xs.Serialize(writer, obj);
}
var s = from text in doc.XPathSelectElements("//*[./text()]") select text.Value;
return string.Join("|", s);
}
}
public class Field
{
static int x = 0;
int y;
public Field()
{
y = ++x;
}
public override string ToString()
{
return y.ToString();
}
public static implicit operator String(Field f)
{
return f==null?null:f.ToString();
}
public static implicit operator Field(String s)
{
return s ?? "nasty hack to make serializer work";
}
}
public class Demo
{
public string P1 { get; set; }
public string X { get; set; } //something to show if we're pulling back results in order defined here, or if the system just goes alphabetically
public string P2 { get; set; }
public int P3 { get; set; }
public DateTime P4 { get; set; }
public Demo P5 { get; set; }
[XmlElement(typeof(String))]
public Field P6 { get; set; }
[XmlElement(typeof(String))]
public Field P7 { get; set; }
public override string ToString()
{
return this.Stringify();
}
}
public class Program
{
public static void Main(string[] args)
{
Demo d = new Demo() { P1 = "test1", X = "expert mode", P2 = "test2", P3 = 3, P4 = DateTime.UtcNow, P5 = new Demo() { P1 = "baby", P2 = "ooh" },P6=new Field(),P7=new Field() };
//d.P5 = d; //this solution's not perfect - e.g. attempt to serialize a circular loop in the object's graph
Console.WriteLine(d.ToString());
Console.WriteLine("done");
Console.ReadKey();
}
}
}
Alternative
[Serializable]
public class Field
{
static int x = 0;
int y;
public string DummyToString { get { return this.ToString(); } set { /*serializer hack*/ } }
[XmlIgnore]
public string DontShowMe { get; set; }
public Field()
{
y = ++x;
DontShowMe = "you shouldn't see this";
}
public override string ToString()
{
return string.Format("string me on #{0}", y);
}
}
//Demo's Field properties no longer require XmlElement attributes; i.e.:
public Field P6 { get; set; }
public Field P7 { get; set; }
NB:
If you have child items which are complex types (e.g. P5 in the above example), how do you want them handled? Should their properties also be pipe delimited (in which case how do you know which properties relate to which objects)?
How should null values be handled - same as blanks (i.e. two pipes with nothing between them), or not output at all?
Would it be better to return the property names as well as values - so you're not reliant on the order / your output's more robust to future changes in class definition?
Perhaps the XMLSerializer on its own better suits your underlying requirement; assuming you want a robust way of representing your object's data?
Within code I want to do something like this:
item.Stage = Stage.Values.ONE;
Where Stage.Values.ONE represents some predefined Stage:
public class Stage
{
[Key]
public virtual int StageId { get; set; }
public string Name { get; set; }
public TimeSpan Span { get; set; }
}
I'm dealing with EF CodeFirst... and I have a lot of stages to define. I'm not sure if I should store the data in the database, or in the dbContext, or what, but I'm looking for the simplest implementation.
I've tried this:
I've tried the following (defining two constants):
public class Stage
{
[Key]
public virtual int StageId { get; set; }
public string Name { get; set; }
public TimeSpan Span { get; set; }
public static class Values
{
public static readonly Stage ONE = new Stage()
{
StageId = 0,
Name = "ONE",
Span = new TimeSpan(0, 0, 0)
};
public static readonly Stage TWO = new Stage()
{
StageId = 1,
Name = "TWO",
Span = new TimeSpan(0, 0, 10)
};
}
But whenever I create a new instance of an entity that has a Stage, a new Stage is added to the db. I just need a few constant stages.
Use of Stage:
public class Side
{
public Side()
{
Stage = Stage.Values.ONE; // Adds new Stage to DB, when it should be a reference to the one I defined above
}
public virtual Stage Stage { get; set; }
}
It looks a bit like an enum, and I've used a kind of 'extended enum' patter several times before with some success. Because you're refencing these values in code, it may not make sense to store them in the database as well, but it's possible if needed.
The technique is described in detail here: http://lostechies.com/jimmybogard/2008/08/12/enumeration-classes/
Basically, you create a base class which provides a number of services similar to an enum, and then to create your "enumerated class" you inherit from it and provide a bunch of static instances which call the constructor with however many properties you need to have.
To avoid link rot, here is the base class to use (just put the whole class into your project somewhere), and scroll down for your own code.
public abstract class Enumeration : IComparable
{
private readonly int _value;
private readonly string _displayName;
protected Enumeration()
{
}
protected Enumeration(int value, string displayName)
{
_value = value;
_displayName = displayName;
}
public int Value
{
get { return _value; }
}
public string DisplayName
{
get { return _displayName; }
}
public override string ToString()
{
return DisplayName;
}
public static IEnumerable<T> GetAll<T>() where T : Enumeration, new()
{
var type = typeof(T);
var fields = type.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly);
foreach (var info in fields)
{
var instance = new T();
var locatedValue = info.GetValue(instance) as T;
if (locatedValue != null)
{
yield return locatedValue;
}
}
}
public override bool Equals(object obj)
{
var otherValue = obj as Enumeration;
if (otherValue == null)
{
return false;
}
var typeMatches = GetType().Equals(obj.GetType());
var valueMatches = _value.Equals(otherValue.Value);
return typeMatches && valueMatches;
}
public override int GetHashCode()
{
return _value.GetHashCode();
}
public static int AbsoluteDifference(Enumeration firstValue, Enumeration secondValue)
{
var absoluteDifference = Math.Abs(firstValue.Value - secondValue.Value);
return absoluteDifference;
}
public static T FromValue<T>(int value) where T : Enumeration, new()
{
var matchingItem = parse<T, int>(value, "value", item => item.Value == value);
return matchingItem;
}
public static T FromDisplayName<T>(string displayName) where T : Enumeration, new()
{
var matchingItem = parse<T, string>(displayName, "display name", item => item.DisplayName == displayName);
return matchingItem;
}
private static T parse<T, K>(K value, string description, Func<T, bool> predicate) where T : Enumeration, new()
{
var matchingItem = GetAll<T>().FirstOrDefault(predicate);
if (matchingItem == null)
{
var message = string.Format("'{0}' is not a valid {1} in {2}", value, description, typeof(T));
throw new ApplicationException(message);
}
return matchingItem;
}
public int CompareTo(object other)
{
return Value.CompareTo(((Enumeration)other).Value);
}
}
And now your code will look something like this:
public class Stage : Enumeration
{
public TimeSpan TimeSpan { get; private set; }
public static readonly Stage One
= new Stage (1, "Stage one", new TimeSpan(5));
public static readonly Stage Two
= new Stage (2, "Stage two", new TimeSpan(10));
public static readonly Stage Three
= new Stage (3, "Stage three", new TimeSpan(15));
private EmployeeType() { }
private EmployeeType(int value, string displayName, TimeSpan span) : base(value, displayName)
{
TimeSpan = span;
}
}
Once you have that set up, you can just store the .Value in the database. I'm afraid I haven't done it in EF, but in nHibernate it's reasonably straight-forward to tell a property to just store the ".Value" of the property, and you can wire it back up when you load the value by having it call:
Stage.FromValue<Stage>(intValue);
Hold the Stage as a property of your entity, use it the way you're doing and add
Ignore(x => x.Stage)
to your mapping. This will ignore this property when mapping to your database.
Edit: I misinterpreted the question.
If you want just the different stages in your database, you should put the stages in their own table with an ID, and refer to that ID trough a relationship. Every entity will hold an additional reference and you'll have to define relationships for them.
Is this what you were looking for?
I have this code (which is way simplified from the real code):
public interface IAmount
{
decimal Amount { get; set; }
}
public class SomeAmount : IAmount
{
public decimal Amount { get; set; }
}
public static void UpdateAmounts( this IEnumerable< IAmount > amounts, decimal totalAmount )
{
foreach ( IAmount amount in amounts )
amount.Amount = GetAmount();
}
public static decimal GetAmount()
{
return 12345m;
}
The code works great and the UpdateAmounts ExtensionMethod is used quite frequently throughout the application to apply a penny rounding routine (not like the one in Office Space!)
The problem is I do not like having an IAmount interface with a specific name of the column I need to set (Amount). In a new requirement, I need to update a database entity collection with this routine and the name of the property I need to update is "GrossAmount". Sometimes too it would be nice to update other writable decimal properties in a similar manner.
The problem is that it appears I cannot simple say amount.Field = GetAmount() where the .Field part deals with a different property on the entity. Is it possible somehow? I am not on C# 4.0, so using a dynamic type isn't possible for me yet.
You could do this in a more functional style, something like this:
public class Something
{
public decimal Amount { get; set; }
public decimal OtherAmount { get; set; }
}
public static void UpdateAmounts<T, U>(IEnumerable<T> items, Action<T,U> setter, Func<T, U> getter)
{
foreach (var o in items)
{
setter(o, getter(o));
}
}
public void QuickTest()
{
var s = new [] { new Something() { Amount = 1, OtherAmount = 11 }, new Something() { Amount = 2, OtherAmount = 22 }};
UpdateAmounts(s, (o,v) => o.Amount = v, (o) => o.Amount + 1);
UpdateAmounts(s, (o,v) => o.OtherAmount = v, (o) => o.OtherAmount + 2);
}
What about having a Dictionary-like interface ?
public interface IAmount {
decimal this[string fieldName] { get; set; }
}
Implementation is simply:
public class Money : IAmout {
private Dictionary<string, decimal> _dict;
public decimal this[string fieldName] {
get { return _dict[fieldName]; }
set { _dict[fieldName] = value; }
}
}
(of course, it requires some error checking)
Then, one can write:
Money m = new Money();
m["Amount"] = ...
or
m["GrossAmount"] = ...
Not as nice as dynamic, I agree.
public class SomeAmount : IAmount
{
decimal amount;
public decimal Amount
{
get{return this.amount;}
set{this.amount=value; }
}
}
Not sure how willing you are to screw with your entities, but...
public class SomeGrossAmount : IAmount
{
public decimal GrossAmount { get; set; }
decimal IAmount.Amount
{
get { return GrossAmount; }
set { GrossAmount = value; }
}
}
This hides the Amount implementation of your entity in any context that it's not directly used as an IAmount, while still allowing it to function as an IAmount.
You could hide the Field property, like this:
public interface IAmount
{
decimal Field
{ get; set; }
}
public class SomeAmount : IAmount
{
public decimal Amount
{ get; set; }
decimal IAmount.Field
{
get { return Amount; }
set { Amount = value; }
}
}
public class SomeGrossAmount : IAmount
{
public decimal GrossAmount
{ get; set; }
decimal IAmount.Field
{
get { return GrossAmount; }
set { GrossAmount= value; }
}
}
Casting the object to IAmount reveals the Field for your purposes. Otherwise, Field is hidden in the designer and Amount (or GrossAmount) is what you'll be working with.
You could also use reflection in order to apply your rounding on every decimal inside your type.
public static void UpdateAmounts( this IEnumerable< IAmount > amounts, decimal totalAmount )
{
foreach ( IAmount amount in amounts )
{
var myType = amount.GetType();
var myTypeProperties = myType.GetProperties();
foreach (PropertyInfo h_pi in myTypeProperties)
{
if (h_pi.Property_Type == typeof(decimal)) // or h_pi.Name == "Amount" || h_pi.Name == "GrossAmount"...
{
//DoStuff
}
}
}
amount.Amount = GetAmount();
}
there is better way to write that but I'm sure you get the point. Using reflection you could also get rid of the whole interface thing and simply go by reflection.
P.S. : Reflection is not the fastest way to go but it's an easy way to get runtime flexibility.
Let me know if that's what you wanted...
Or, when you do not mind using reflection (it is a bit slower): it is very powerful in combination with attributes. First, create an attribute used to mark the decimal property you need:
[AttributeUsage(AttributeTargets.Property,
Inherited = true, AllowMultiple = false)]
sealed class DecimalFieldAttribute : Attribute
{
public DecimalFieldAttribute()
{ }
}
Mark your field with the attribute, e.g.:
public class SomeGrossAmount
{
[DecimalField]
public decimal GrossAmount
{
get;
set;
}
}
Then use this method to set such a field:
public static void SetDecimalField(object obj, decimal value)
{
// Enumerate through all the properties to find one marked
// with the DecimalFieldAttribute.
PropertyInfo[] properties = obj.GetType().GetProperties();
PropertyInfo decimalfieldproperty = null;
foreach (PropertyInfo property in properties)
{
object[] attributes = property.GetCustomAttributes(typeof(DecimalFieldAttribute), true);
if (attributes.Length == 0)
continue;
// Check, or just break; when you'll not be making this error.
if (decimalfieldproperty != null)
throw new Exception("More than one property is marked with the DecimalFieldAttribute.");
// Found a candidate.
decimalfieldproperty = property;
}
// Check, or just assume that you'll not be making this error.
if (decimalfieldproperty == null)
throw new Exception("No property with the DecimalFieldAttribute found.");
// Set the value.
decimalfieldproperty.SetValue(obj, value, null);
}
I would suggest something like this:
public class Entity
{
public decimal Amount { get; set; }
public decimal OtherAmount { get; set; }
}
public static void Update<TEntity, TValue>(this IEnumerable<TEntity> entities, Func<TValue> valueGetter, Action<TEntity, TValue> valueSetter)
{
foreach (TEntity entity in entities)
{
TValue value = valueGetter.Invoke();
valueSetter.Invoke(entity, value);
}
}
public static decimal GetAmount()
{
throw new NotImplementedException();
}
public static decimal GetOtherAmount()
{
throw new NotImplementedException();
}
public static IEnumerable<Entity> GetEntities()
{
throw new NotImplementedException();
}
static void Main()
{
IEnumerable<Entity> entities = GetEntities();
entities.Update<Entity, decimal>(GetAmount, (entity, value) => entity.Amount = value);
entities.Update<Entity, decimal>(GetOtherAmount, (entity, otherValue) => entity.OtherAmount = otherValue);
}