How to store multiple database columns into an array with Linq2Sql - c#

I have to work with multiple SQL Server tables that generally look like this:
int id_this, int id_that, ..., double Value1, double Value2, ..., double Value96
I know this sucks, but I can't change it. What I want to do now is to define some class like
public class Foo
{
public int Id_This { get; set; }
public int Id_That { get; set; }
...
public double Value[];
}
The Value-Array being a property of course, but I think you get the idea.
The question is, how to get the 96 columns into the array as painlessly as possible.
I could do that with a plain SqlDataReader, since DataRow allows indexed access, but I wonder if I could declare some attributes or write some minimum amount of code to use the class directly with LINQ2SQL.
As a minimum, I would like to do
dataContext.ExecuteQuery<Foo>("SELECT * FROM Foo");

Ooh, that is... nice? The DataContext methods always expect an entity type; there is no ExecuteReader, which is a pain (but understandable, as it wants to behave as an ORM). To be honest, I would be tempted to use ADO.NET for the guts against this table, but if you have mapped the wide table to the DataContext you should be able to use either regular C# or reflection.
Since the number doesn't change, unless you have multiple tables I'd just bite the bullet and write some ugly code:
Foo foo = new Foo { Id_This = obj.Id_This, Id_That = obj.Id_That,
Values = new double[] {obj.Value1, obj.Value2, ... } };
If you have multiple tables... reflection, perhaps optimised via Expression:
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
class FooUgly
{
public int IdThis { get; set; }
public int IdThat { get; set; }
public double Value1 { get; set; }
public double Value2 { get; set; }
public double Value3 { get; set; }
}
class Foo
{
public int IdThis { get; set; }
public int IdThat { get; set; }
public double[] Values { get; set; }
public Foo() { }
internal Foo(FooUgly ugly)
{
IdThis = ugly.IdThis;
IdThat = ugly.IdThat;
Values = extractor(ugly);
}
// re-use this!!!
static readonly Func<FooUgly, double[]> extractor =
ValueExtractor<FooUgly, double>.Create("Value", 1, 3);
}
static class Program
{
static void Main()
{
FooUgly ugly = new FooUgly { IdThis = 1, IdThat = 2, Value1 = 3, Value2 = 4, Value3 = 5 };
Foo foo = new Foo(ugly);
}
}
static class ValueExtractor<TFrom,TValue>
{
public static Func<TFrom, TValue[]> Create(string memberPrefix, int start, int end)
{
if(end < start) throw new ArgumentOutOfRangeException();
ParameterExpression param = Expression.Parameter(typeof(TFrom), "source");
List<Expression> vals = new List<Expression>();
for(int i = start ; i <= end ; i++) {
vals.Add(Expression.PropertyOrField(param, memberPrefix + i));
}
Expression arr = Expression.NewArrayInit(typeof(TValue), vals);
return Expression.Lambda<Func<TFrom, TValue[]>>(arr, param).Compile();
}
}

Related

C# Interface: extracting additional public property value (not part of interface) from a concrete class

Code sample to begin with:
internal class ClubHouse : ILeasable
{
public int Id { get; set; }
public int AreaInSquareFeet { get; set; }
}
public class Parking : ILeasable
{
public int Id { get; set; }
public int CarCapacity { get; set; }
}
internal interface ILeasable
{
int Id { get; set; }
}
class LeasableRepository
{
private List<ILeasable> _leasable = new List<ILeasable>()
{
new ClubHouse() {Id = 208, AreaInSquareFeet = 7500 },
new ShowRoom(){ Id = 202, AreaInSquareFeet = 4000 },
new Parking() {Id = 504, CarCapacity = 4},
};
private Dictionary<int, ILeasable> _leasableDictionary = new Dictionary<int, ILeasable>();
public LeasableRepository()
{
_leasableDictionary = _leasable.ToDictionary(x => x.Id, x => x);
}
public ILeasable GetLeasable(int id)
{
if (_leasableDictionary.ContainsKey(id)) return _leasableDictionary[id];
return null;
}
}
public class ChargeCalculatingFacade
{
LeasableRepository leasableRepository = new LeasableRepository();
public void ShowLeasingCharges(int id)
{
var leasable = leasableRepository.GetLeasable(id);
var leasingCharge = GetLeasingCharges(leasable);
}
private int GetLeasingCharges(ILeasable leasable)
{
// This is not possible as I can't be sure that leasable is ClubHouse
var property = (ClubHouse) leasable;
var areaInSquareFeet = property.AreaInSquareFeet;
return areaInSquareFeet * 10;
}
}
Now, in class ChargeCalculatingFacade class, in method ShowLeasingCharges(int id), based on the id, I called GetLeasable(int id) which returns one of the implementation of ILeasable. However it return as an interface ILeasable.
I pass that ILeasable to a private method GetLeasingCharges(leasable) to calculate the leasing charges based on the AreaInSquareFeet.
Now, leasable parameter is just ILeasable, which has just "Id" property available. Now how to identify which concreat class implementation is passed as parameter, I can cast it to get AreaInSquareFeet like this
var property = (ClubHouse) leasable;
var areaInSquareFeet = property.AreaInSquareFeet;
But the above code is not posible as I am not sure if the leasable is ClubHouse as it just picks leasable from a dictionary based on Id.
All class does not have the same additional property. For instance, Parking has additional property as "CarCapacity". I have 10 such classes, now cannot put 10 if logic to check if the interface is of required class type.
I wonder if some design pattern or some SOLID principle can simplify the design.
I have following questions:
How do I get the areaInSquareFeet in such case
Is this a good practice to have an interface with few methods and properties and again have additional public methods or properties in concreate class.
Note: I do not want to use reflection. I would like to change a design in case without reflection is not possible. Any design suggestions? Any desing pattern can be used in such scenario?'
Thank you.
Mita
A. ILeasable.GetLeasingCharges
If GetLeasingCharges depends only on the data the object already has I could be argued that it may be better choice to make GetLeasingCharges part of ILeasable.
internal interface ILeasable
{
int Id { get; set; }
int GetLeasingCharges();
}
internal class ClubHouse : ILeasable
{
public int Id { get; set; }
public int AreaInSquareFeet { get; set; }
public int GetLeasingCharges() => AreaInSquareFeet * 10;
}
internal class ClubHouse : ILeasable
{
public int Id { get; set; }
public int CarCapcity{ get; set; }
public int GetLeasingCharges() => CarCapcity * 15;
}
B. GetLeasingCharges not part ILeasable
From C#7.0 you can use pattern matching for situations like this.
public static int GetLeasingCharges(ILeasable leasable)
{
// From c#7.0
switch (leasable)
{
case ClubHouse c:
return c.AreaInSquareFeet * 10;
case ShowRoom s:
return s.AreaInSquareFeet * 12;
case Parking p:
throw new ArgumentException(
message: "Parkings cannot be leased!",
paramName: nameof(leasable));
default:
throw new ArgumentException(
message: "Unknown type",
paramName: nameof(leasable));
}
}
Before C#7.0 you could use if.
if (leasable is ClubHouse)
{
var c = (ClubHouse)leasable;
return c.AreaInSquareFeet * 10;
}
else if (leasable is ShowRoom)
{
var c = (ShowRoom)leasable;
return s.AreaInSquareFeet * 12;
}
else if(leasable is Parking)
{
throw new ArgumentException(
message: "Parkings cannot be leased!",
paramName: nameof(leasable));
}
else
{
throw new ArgumentException(
message: "Unknown type",
paramName: nameof(leasable));
}
I quite agree with #tymtam approach. You can also use an abstract class in an alternative.
public abstract class ChargeCalculatingFacadeBase<T> where T : ILeasable
{
LeasableRepository leasableRepository = new LeasableRepository();
public ILeasable leasable;
public void ShowLeasingCharges(int id)
{
leasable = leasableRepository.GetLeasable(id);
var leasingCharge = GetLeasingCharges((T)leasable);
}
public abstract int GetLeasingCharges(T leasable);
}
public class ChargeCalculatingFacade : ChargeCalculatingFacadeBase<ClubHouse>
{
public override int GetLeasingCharges(ClubHouse leasable)
{
var property = leasable;
var areaInSquareFeet = property.AreaInSquareFeet;
return areaInSquareFeet * 10;
}
}
While this might be an overkill, in a case similar to yours I have on a few occasions used a pseudo-DSL approach.
That is, I first come up with a language to express my intent, and then implement it.
What do you need? The ability to express calculations in a readable way. Let's do it this way: assuming you have a class
public class LeaseCalculator
{
public int CalculateLease(int id) ...
I'd like to initialize it like this:
var builder = new LeaseCalculatorBuilder();
LeaseCalculator calculator = builder
.On<ClubHouse>(house => house.AreaInSquareFeet)
.On<Parking>(park => park.CarCapacity)
.On<ShowRoom>(room => room.AreaInSquareFeet)
.Build(leasableRepository);
Is the intent clear? I believe so. If we have a club house, we do the first thing; for parking, something else, etc, etc.
Now, to the implementation. I could also walk step by step, but to cut story short:
public class LeaseCalculatorBuilder
{
internal Dictionary<Type, Func<ILeasable, int>> Calculations { get; } = new Dictionary<Type, Func<ILeasable, int>>();
internal LeaseCalculatorBuilder On<T>(Func<T, int> calculation) where T : class, ILeasable
{
Calculations.Add(typeof(T), (ILeasable c) => calculation((T)c));
return this;
}
internal LeaseCalculator Build(LeasableRepository leasableRepository)
{
return new LeaseCalculator(leasableRepository, this);
}
}
public class LeaseCalculator
{
private readonly Dictionary<Type, Func<ILeasable, int>> _calculations;
private readonly LeasableRepository _leasableRepository;
internal LeaseCalculator(LeasableRepository leasableRepository, LeaseCalculatorBuilder builder)
{
_leasableRepository = leasableRepository;
_calculations = builder.Calculations;
}
public int CalculateLease(int id)
{
ILeasable property = _leasableRepository.GetLeasable(id);
Type type = property.GetType();
if (_calculations.TryGetValue(type, out var calculation))
{
return calculation(property);
}
throw new Exception("Unexpected type, please extend the calculator");
}
}
And finally, a default creator:
public static class DefaultLeaseCalculator
{
internal static LeaseCalculator Build(LeasableRepository leasableRepository)
{
var builder = new LeaseCalculatorBuilder();
LeaseCalculator calculator = builder
.On<ClubHouse>(house => house.AreaInSquareFeet)
.On<Parking>(park => park.CarCapacity)
.On<ShowRoom>(room => room.AreaInSquareFeet)
.Build(leasableRepository);
return calculator;
}
}
Neat?

Performing calculations on properties generically and fast

The goal is to create a method which generically performs calculations on a property of a list of objects in a performant manner. Below is the entire test code:
using System;
using System.Collections.Generic;
namespace TestApp
{
public class Minute
{
public DateTime DateTimeUtc { get; set; }
public float Source { get; set; }
public float Mult2 { get; set; }
public float Mult3 { get; set; }
public float Mult4 { get; set; }
}
class Program
{
public static List<Minute> Minutes = new List<Minute>();
static void Main(string[] args)
{
for (int i = 1; i < 10000000; i++)
{
Minute newMinute = new Minute();
newMinute.Source = i;
Minutes.Add(newMinute);
}
GenerateMult2(Minutes, 2); // 160 ms
GenerateMult2Generic(Minutes, typeof(Minute), nameof(Minute.Source), nameof(Minute.Mult2),2); // 4300 ms
}
public static void GenerateMult2(List<Minute> Minutes, int multiplier)
{
for (int i = 0; i < Minutes.Count; i++)
{
// Simplified calculation, there will eventually be a lot more code that goes here!
Minutes[i].Mult2 = Minutes[i].Source * multiplier;
}
}
public static void GenerateMult2Generic<T>(List<T> SourceList, Type ContainerType, string propNameSource, string propNameMult, int multiplier)
{
var propertyInfoSource = ContainerType.GetProperty(propNameSource);
var propertyInfoMult = ContainerType.GetProperty(propNameMult);
foreach (T item in SourceList)
{
float sourceValue = (float)propertyInfoSource.GetValue(item);
propertyInfoMult.SetValue(item, sourceValue * multiplier);
}
}
}
}
In this test app there is a method called GenerateMult2, whose purpose is to make some calculation on one of the properties in a list of Minute objects. This method works fine and is fast. The problem is that the method is too specific. If I wanted to do the same calculations on the properties Mult3 and Mult4, I would need to make a separate method for each of these properties, which is too much duplicated code. I want to make this method more generic, which is, I want the method to accept lists of other types as well, for example a list of Day objects or Second objects. Furthermore, I want to tell the method which property to perform the calculations on.
So I've made an attempt at creating a generic method called GenerateMult2Generic. This method performs the exact same calculation as the GenerateMult2 method, and is multipurpose, which is what I want. The huge disadvantage is that it's way too slow due to the reflections.
How can the GenerateMult2 method be made in a generic fashion, but with a performance penalty of no more than 5%?
Update with solution
Having studied the answers here, the best is one that was given by Ed Plunkett, but somehow was removed. Therefore, I'm posting the original code updated with the ideas from that answer:
using System;
using System.Collections.Generic;
using System.Linq;
namespace TestApp
{
public class Minute : BaseTime
{
public float MovingAverageFast { get; set; }
public float MovingAverageSlow { get; set; }
public float RsiFast { get; set; }
public float RsiSlow { get; set; }
}
public class Day : BaseTime
{
public float MovingAverageFast { get; set; }
public float MovingAverageSlow { get; set; }
public float RsiFast { get; set; }
public float RsiSlow { get; set; }
}
public class BaseTime
{
public DateTime DateTimeUtc { get; set; }
public float Source { get; set; }
}
class Program
{
public static List<Minute> Minutes = new List<Minute>();
public static List<Day> Days = new List<Day>();
static void Main(string[] args)
{
Minutes = Enumerable.Range(1, 10000000).Select(n => new Minute { Source = n }).ToList();
Days = Enumerable.Range(1, 10000000).Select(n => new Day { Source = n }).ToList();
// Generating data for Minutes
GenerateMovingAverage(Minutes, 100, (m, value) => ((Minute)m).MovingAverageFast = value);
GenerateMovingAverage(Minutes, 500, (m, value) => ((Minute)m).MovingAverageSlow = value);
GenerateRsi(Minutes, 60, (m, value) => ((Minute)m).RsiFast = value);
GenerateRsi(Minutes, 250, (m, value) => ((Minute)m).RsiSlow = value);
// Generating data for Days
GenerateMovingAverage(Days, 8, (d, value) => ((Day)d).MovingAverageFast = value);
GenerateMovingAverage(Days, 45, (d, value) => ((Day)d).MovingAverageSlow = value);
GenerateRsi(Days, 5, (d, value) => ((Day)d).RsiFast = value);
GenerateRsi(Days, 21, (d, value) => ((Day)d).RsiSlow = value);
}
public static void GenerateMovingAverage(IEnumerable<BaseTime> BaseTimeObjects, int Period, Action<BaseTime, float> setter)
{
foreach (var BaseTimeObject in BaseTimeObjects)
{
float newValue;
newValue = BaseTimeObject.Source * Period; // pseudo calculation for generating moving average
setter(BaseTimeObject, newValue);
}
}
public static void GenerateRsi(IEnumerable<BaseTime> BaseTimeObjects, int Period, Action<BaseTime, float> setter)
{
foreach (var BaseTimeObject in BaseTimeObjects)
{
float newValue;
newValue = BaseTimeObject.Source / Period; // pseudo calculation for generating rsi
setter(BaseTimeObject, newValue);
}
}
}
}
The key idea here is setting the property via an Action in the caller. With this solution, the calculation methods are reused for any object and any property with good performance.
In addition to what #iSR5 wrote, you might consider using a factory design pattern, making classes that do the actual calculations. This would be good if you don't know what you actually need to do until run time.
public interface IMultiValueGenerator
{
void GenerateValue(ITimeMulti multi, int multiplier);
}
public class Multi2Generator : IMultiValueGenerator
{
public void GenerateValue(ITimeMulti multi, int multiplier)
{
multi.Mult2 = multi.Source * multiplier;
}
}
public static class MultiGeneratorFactory
{
public static IMultiValueGenerator GetGenerator(...)
{
if (condition)
return new Multi2Generator();
// etc
}
}
Not sure if I've got the full picture here, but from my understanding, you'll need to have an interface with a base class. The interface is the one that you'll use to define the object, while the base class is the container for all common operations, which can be inhered by the class children. Then, you can create child class (as many as you want) and inherit the base class. The child class will have its required properties, methods, and logic if needed.
Enough talking, let's take it in code :
interface ITimeMulti
{
DateTime DateTimeUtc { get; set; }
float Source { get; set; }
// will be used for number of available properties.
int MultCount { get; }
// the main method for generating the multipliers.
void Generate(int multNumber, int multiplier);
}
Simple ? let's now create the base class :
public class TimeMulti : ITimeMulti
{
public DateTime DateTimeUtc { get; set; }
public float Source { get; set; }
// Using Dictionary will be much faster than Reflection
protected static Dictionary<string, float> Multipliers { get; set; }
// Number of Properties (the set should be within the derived classes)
public int MultCount { get; protected set; }
// This is a restriction to create this instance from the derived classes only
private TimeMulti() { }
// for derived classes
protected TimeMulti(int multCount)
{
// Should be in this constructor only
Initiate(multCount);
}
// This is the main method to generate the multiplication part.
public void Generate(int multNumber, int multiplier)
{
if (multNumber == 0)
{
Multipliers["Mult"] = Source * multiplier;
}
else if (Multipliers.ContainsKey("Mult" + multNumber))
{
// store the value in the dictionary (this is for reference)
Multipliers["Mult" + multNumber] = SetMult(multNumber, Source * multiplier);
}
else
{
throw new NullReferenceException();
}
}
// On new instance, this will fired, which will setup the dictionary
protected void Initiate(int numberOfMultipliers)
{
// Ensure you have an active instance of the dictionary
if (Multipliers == null)
Multipliers = new Dictionary<string, float>();
// Ensurance
if(numberOfMultipliers > 0)
{
MultCount = numberOfMultipliers;
for (int x = 1; x <= numberOfMultipliers; x++)
if (!Multipliers.ContainsKey("Mult" + x))
Multipliers.Add("Mult" + x, 0);
}
else
{
throw new ArgumentOutOfRangeException();
}
}
// this is where we will replace Reflection, here is just returning the multValue
// we will override it on the derived classes
protected virtual float SetMult(int MultNumber, float multValue) => multValue;
}
Now, the derived class
public class Minute : TimeMulti
{
public float Mult1 { get; set; }
public float Mult2 { get; set; }
public float Mult3 { get; set; }
public float Mult4 { get; set; }
// MultCount = 4
public Minute(): base(4) { }
// This method will set the value of the property using switch statment, with this, you will avoid Reflection.
protected override float SetMult(int multNumber, float multValue)
{
switch (multNumber)
{
case 1:
Mult1 = multValue;
break;
case 2:
Mult2 = multValue;
break;
case 3:
Mult3 = multValue;
break;
case 4:
Mult4 = multValue;
break;
}
return multValue;
}
}
Now, you can do this :
class Program
{
// Create List with type of the ITimeMulti interface
public static List<ITimeMulti> Minutes = new List<ITimeMulti>();
static void Main(string[] args)
{
// Generate a sample
for (int i = 1; i < 10000000; i++)
Minutes.Add(new Minute() { Source = i});
// Calculate
GenerateMultipliers(Minutes, 1, 2);
}
public static void GenerateMultipliers(List<ITimeMulti> source, int multNumber, int multiplier)
{
for (int i = 0; i < source.Count; i++)
{
source[i].Generate(multNumber, multiplier);
}
}
}
If you want to create a new derived class :
public class Day : TimeMulti
{
// Properties
public float Mult1 { get; set; }
// Constructor
public Day(): base(1) { }
// This method to map the values to the properties
protected override float SetMult(int multNumber, float multValue)
{
switch (multNumber)
{
case 1:
Mult1 = multValue;
break;
}
return multValue;
}
}
This is just an example to give you a new ideas, you can do your own magic. I wouldn't go with Mult1 ...etc. I would go with a unique and a descriptive names.
Updated :
You can improve the performance of your updated code, by gathering all common properties in the base and make use of virtual and override if you want to have something override-able in a child class. Or, use interface and struct instead of classes. Also, instead of using IEnumerable use Array this would improve your performance as well.
public class BaseTime
{
// shared proprties
public DateTime DateTimeUtc { get; set; }
public float Source { get; set; }
public float MovingAverageFast { get; set; }
public float MovingAverageSlow { get; set; }
public float RsiFast { get; set; }
public float RsiSlow { get; set; }
}
public class Minute : BaseTime
{
// add your custom code for Minute
// No need for recreating them, since it's already inherited from the base
}
public class Day : BaseTime
{
// add your custom code for Day
// No need for recreating them, since it's already inherited from the base
}
class Program
{
public static BaseTime[] Minutes;
public static BaseTime[] Days;
static void Main(string[] args)
{
Minutes = Enumerable.Range(1, 10000000).Select(n => (BaseTime) new Minute { Source = n }).ToArray();
Days = Enumerable.Range(1, 10000000).Select(n => (BaseTime) new Day { Source = n }).ToArray();
// Generating data for Minutes
GenerateMovingAverage(Minutes, 100, (m, value) => m.MovingAverageFast = value);
GenerateRsi(Minutes, 60, (m, value) => m.RsiFast = value);
GenerateRsi(Minutes, 250, (m, value) => m.RsiSlow = value);
// Generating data for Days
GenerateMovingAverage(Days, 8, (d, value) => d.MovingAverageFast = value);
GenerateMovingAverage(Days, 45, (d, value) => d.MovingAverageSlow = value);
GenerateRsi(Days, 5, (d, value) => d.RsiFast = value);
GenerateRsi(Days, 21, (d, value) => d.RsiSlow = value);
}
public static void GenerateMovingAverage(BaseTime[] BaseTimeObjects, int Period, Action<BaseTime, float> setter)
{
foreach (var BaseTimeObject in BaseTimeObjects)
{
setter(BaseTimeObject, BaseTimeObject.Source * Period);
}
}
public static void GenerateRsi(BaseTime[] BaseTimeObjects, int Period, Action<BaseTime, float> setter)
{
foreach (var BaseTimeObject in BaseTimeObjects)
{
setter(BaseTimeObject, BaseTimeObject.Source / Period);
}
}
}

Create Generic Method that accepts a List with custom object types and access similar properties

I am creating a search algorithm that searches through a list with custom objects I have created. They share similar properties, but I can not seem to "implicitly" access these properties..? An example:
public class Exit{
int ID {get;set;}
}
public class Room{
int ID {get;set;}
}
static void Main(string[] args){
List<Exit> exits = new List<Exit>();
List<Room> rooms = new List<Room>();
// added numerous instances of objects to both lists
int getExitID = _GetIDFromList(exits, 2); //example
int getRoomID = _GetIDFromList(rooms, 7); //example
}
private int _GetIDFromList<T>(List<T> list, int indexOfList){
return list[indexOfList].ID; // this gives me error it can't find ID
}
Is this possible? What do I need to modify to what I have to do this??
Thank you.
You can create interface for it:
public interface IId
{
int ID { get; set; }
}
public class Exit : IId
{
int ID { get; set; }
}
public class Room : IId
{
int ID { get; set; }
}
private int _GetIDFromList<T>(List<T> list, int indexOfList) where T : IId
{
return list[indexOfList].ID;
}
Or you can use Reflection and Expression for it:
public static Expression<Func<T, P>> GetGetter<T, P>(string propName)
{
var parameter = Expression.Parameter(typeof(T));
var property = Expression.PropertyOrField(parameter, propName);
return Expression.Lambda<Func<T, P>>(property, parameter);
}
Retrives int Id from type T and returns it:
private static int _GetIDFromList<T>(List<T> list, int indexOfList)
{
var lambda = GetGetter<T, int>("Id").Compile();
return lambda(list[indexOfList]);
}
I'm little rewrote your Room class:
public class Room
{
public int ID { get; set; }
}
And usage:
Console.WriteLine(_GetIDFromList(new List<Room> { new Room { ID = 5 } }, 0));

Odd behavior when adding to an Observable Collection

I have an interesting problem. I have a Class Person:
public class Person
{
public string Name { get; set; }
public int? Score { get; set; }
public int NbrOfWins { get; set; }
public int NbrOfLosses { get; set; }
public int HighScore { get; set; }
}
I create an Observable collection:
ObservableCollection<Person> test = new ObservableCollection<Person>();
I have an extension method to add to the observable collection:
public static void myFillTest<T>(this ObservableCollection<T> value1, T value2, int nbr)
{
for (int x = 0; x < nbr; x++)
{
value1.Add(value2);
}
}
I add 5 items to the collection like this:
test.myFillTest(new Person { Name = "None" }, 5);
If I change the name in one instance:
test[2].Name = "John";
All of the items in the collection change, as if they were all pointing to the same thing.
Any reason why this would be? By the way, this works for T of type int, and string, but not for a typeof class.
This is because the class Person is a reference type while the integer is value type. When you add the same int 5 times, it is copied, when you add person 5 times, its one instance added to 5 different indexes. You can read about reference types here http://msdn.microsoft.com/en-us/library/490f96s2.aspx . You need to copy your object of type person if you want it to work as expected.
You can change your code to the following in order to always create new objects:
public static void MyFillTest<T>(this ObservableCollection<T> value1, T value2, int nbr)
{
for (int x = 0; x < nbr; x++)
{
if (typeof(T).IsValueType)
{
value1.Add(value2);
}
else
{
if (value2 is ICloneable)
{
ICloneable cloneable = (ICloneable)value2;
value1.Add((T)cloneable.Clone());
}
}
}
}
public class Person : ICloneable
{
public string Name { get; set; }
public int? Score { get; set; }
public int NbrOfWins { get; set; }
public int NbrOfLosses { get; set; }
public int HighScore { get; set; }
#region ICloneable Members
public object Clone()
{
return new Person
{
Name = this.Name,
Score = this.Score,
NbrOfWins = this.NbrOfWins,
NbrOfLosses = this.NbrOfLosses,
HighScore = this.HighScore
};
}
#endregion
}
new Person { Name = "None" } is only instantiated once, when you call your method. So they all reference to the same object.
It's quite simple - you are adding value2 to the collection nbr times. Or rather, when adding an object (as you are in your example) you are adding a reference to the same object nbr times. So if you change one, you change them all.
This extension method will do what you are trying to do:
public static void myFillTest<T>(this ObservableCollection<T> value1, Action<T> init, int nbr) where T: new()
{
for (int x = 0; x < nbr; x++)
{
var value2 = new T();
init(value2);
value1.Add(value2);
}
}
Call it like this:
test.myFillTest(p => p.Name = "None", 5);
The Person object is instantiated once and its reference is used 5 times. You could overcome this by using a memberwise clone to create shallow copies of your original object.

comparing versions of the same object

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.

Categories