Here's some very contrived C# code from LinqPad (I can't share the actual code):
void Main()
{
var d = new DemonstrateIssue();
Assert.Throws<ArgumentOutOfRangeException>(() => {bool result = !d.test1.Contains("y");});
Assert.Throws<ArgumentOutOfRangeException>(() => {bool result = !d.test2.Contains("y");});
Assert.Throws<ArgumentOutOfRangeException>(() => {bool result = !d.test3.Contains("y");});
}
// You can define other methods, fields, classes and namespaces here
public class DemonstrateIssue
{
Dictionary<string, string> myTests;
public string test1 {get;}
public string test2 {get;}
public string test3 {get;}
public DemonstrateIssue()
{
myTests = new Dictionary<string, string>()
{
{"test1","yes"},
{"test2","yep"},
{"test3","oh yeah!"}
};
test1 = myTests["test1"];
test2 = myTests["test2"];
test3 = myTests["test3"];
}
}
I'm doing tests with NUnit to check that each property conforms to the same behavior. The thing is, as you can see, it's basically the same test each time except for the class field I'm calling it on. When I see code of that sort I always want to replace it with generic code but I can't figure out how to get each property in a generic fashion. It seems like I need to use reflection but I was hoping there might be some generic way to code this.
I mean I was thinking of something like this
public void TestField<T>()
{
Assert.Throws<ArgumentOutOfRangeException>(() => {bool result = id.T.contains("y");});
}
Where T would be the string field but I can't figure out how to do this if it's even possible. Any suggestions or thoughts on how I might DRY up this code would be greatly appreciated!
Use lambda expression to store the properties in a list. Then iterate over the list and test each element.
void Main()
{
var d = new DemonstrateIssue();
var properties = new List<Func<DemonstrateIssue,string>>
{
x => x.test1,
x => x.test2,
x => x.test3
};
foreach (var p in properties)
{
Assert.Throws<ArgumentOutOfRangeException>(() => bool result = !p(d).Contains("y");});
}
}
Related
I would like to find out which of the properties in a source input object, a method has used. After executing the method I need to store in a database which of the properties was used.
The input could be any class with simple types, like this:
public class MyData : IMyData
{
public string A { get; set; }
public int B { get; set; }
public decimal C { get; set; }
}
I thought it could be done using an interface as input to the method, so I can replace the original object with a more advanced object, which stores usage of properties
public interface IMyData
{
string A { get; }
int B { get; }
decimal C { get; }
}
I can then
Create a dynamic object with the same properties
Use ImpromptuInterface to simulate the dynamic object implements my interface
Call my method with this dynamic interface
private static void Main()
{
var data = new MyData { A = "Test", B = 3, C = new decimal(1.2) };
IDictionary<string, object> replacementObject = new ExpandoObject();
replacementObject.Add("FieldsUsed", new List<string>());
foreach (var property in data.GetType().GetProperties())
replacementObject.Add(property.Name, property.GetValue(data));
var replacementInterface = replacementObject.ActLike<IMyData>();
DoStuff(replacementInterface);
Console.WriteLine($"The method used these fields {string.Join(", ", (List<string>)replacementObject["FieldsUsed"])}");
}
private static void DoStuff(IMyData source)
{
Console.WriteLine($"A is {source.A}");
if (source.B > 5)
Console.WriteLine($"C is {source.C}");
}
In the above example I would like to store that fields A and B have been used.
Only I am stuck at how I should store when a property is used by my DoStuff method.
You can write a wrapper like this:
public class ClassWrapper<T>: DynamicObject where T:class
{
private readonly T _obj;
private readonly List<string> _fieldsUsed=new List<string>();
public ClassWrapper(T obj)
{
_obj = obj;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
PropertyInfo propertyInfo = _obj.GetType().GetProperty(binder.Name);
_fieldsUsed.Add(binder.Name);
result = propertyInfo.GetValue(_obj);
return true;
}
public List<string> GetFieldsUsed() => _fieldsUsed;
public T GetWrapper()
{
return this.ActLike<T>();
}
}
and use it like
var data = new MyData { A = "Test", B = 3, C = new decimal(1.2) };
var mc=new ClassWrapper<IMyData>(data);
IMyData wrapped = mc.GetWrapper();
DoStuff(wrapped);
Console.WriteLine($"The method used these fields {string.Join(", ", (List<string>)mc.GetFieldsUsed())}");
If you want to know when a property is used, a Interface like INotifyPropertyChanged can do that for you at runtime. The exampel is only about notification for writes (that actually changed a value), but it would be trivial to expand it to reads and writes. It is not a perfect thing of course, as different executions might follow different code paths that use different properties.
If a function takes a specific type as input, you have to asume that all properties may be relevant. This is especially true for abstract types and interfaces - often the interface exists for this function. If it is one of those two, you can also always provide your own implementation of those Interfaces and Abstract class.
I can not shake the feeling that this is a XY problem.
So I have an object with lots of properties, PropertyNameYear1, PropertyNameYear2, PropertyNameYear3...for 20 years. these properties could potentially grow with time, so in the future I might have to add PropertyNameYear21 and so on.
I'm trying to get these properties, both their name and value, without specifying each and every one, since theoretically i can have tens of them. I can do it using LINQ and Object Initializer, but then I have to specify each property twice:
new {
PropertyNameYear1 = f => f.PropertyNameYear1,
PropertyNameYear2 = f => f.PropertyNameYear2,
...
};
How can I, using LINQ (and Refelction?), get all these properties (and only these, assuming there are other properties named differently than PropertyNameYearX) into a new/another object and return that object?
This is a pseudo-code of what I'm looking for:
public ReturnType GetSomeObjectWithSpecificProperties(int ID){
var list = SomeObjectRepository.Where(f => f.ID == ID);
var props = list.GetType().GetProperties().ToList();
var SomePropObjectList = props.Where(f => f.Name.Contains("PropertyNameYear")).ToList();
var listToReturn = SomePropObjectList.Select(f => new {
f.Name = f.GetValue(list)
}).ToList();
return listToReturn;
}
I want to pipe in and say you should rethink your approach.
Instead of having:
public class NotGood
{
public int PropertyNameYear1{ get; set; }
//repeat 20 times...
public int PropertyNameYear21{ get; set; }
}
...consider:
public class Better
{
public List<int> PropertyNameYears{ get; } = new List<int>();
}
It's one line of code and it will scale much better. Plus, you eliminate all the clumsy, reflection-based parsing.
EDIT: As I mentioned in the comments, sometimes the proper approach to clean code is discussing bad code with the author vs. adapting your code to fit the problem they caused, but if there's no way around it, here's an approach that requires four lines of code:
var obj = new
{
SomeNormalProp = "foo",
ThisIsSilly1 = 1,
ThisIsSilly2 = 2,
ThisIsSilly3 = 3,
ThisIsSilly4 = 4
};
dynamic barfObj = new ExpandoObject();
foreach (var prop in obj.GetType().GetProperties())
if (prop.Name.StartsWith("ThisIsSilly"))
//add property dynamically
((IDictionary<string, object>)barfObj).Add(prop.Name, prop.GetValue(obj));
//now barfObj is exactly what you want.
var sampleVal = barfObj.ThisIsSilly1;
var json = JsonConvert.SerializeObject(barfObj);
Or if you're a real masochist, you have Reflection.Emit:
How to dynamically create a class in C#?
You can make use of ExpandoObject to dynamically add Properties from your source class object. Assuming the source class is ClassWithMayProperties:
public object GetObject(ClassWithManyPropererties obj)
{
var props = obj.GetType().GetProperties().Where(p => p.Name.Contains("PropertyNameYear")).ToList();
dynamic returnObject = new ExpandoObject() as IDictionary<string, Object>;
foreach (var property in props)
{
returnObject.Add(property.Name, property.GetValue(obj));
}
return returnObject;
}
Then you can directly get the value of property you want or cast the ExpandoObject in IDictionary and check for the property name as key.
var dynObject = GetObject(obj);
var d = dynObject.PropertyNameYear1
var _Contact = new ContactLstModel {
ContactName="xxxxxx",
EmailAddr="yyyyyy",
ContactNo="ddddddd",
SelectedContactType="dddd"
};
var _ContactOption= new ContactLstModel{
ContactType= new List<SelectListItem>(){
new SelectListItem{
Text="sss",Value="ddd"
}
}
};
as you can see both are of the same model ContactLstModel. Now how do I combine both into one?
Like in jQuery, we have $.extend(dest,source);
Is there an equivalent in C#?
There is not a built-in equivalent of $.extend in C# and .NET 4.5.
However you can find many examples of people trying to achieve that kind of behavior using reflection in .NET. There are others who use serialization (JSON.NET etc.) to achieve similar behaviors . Another approach would be to use IOC containers like Automapper.
Here is an example how to merge your first object into the second object using Automapper IOC:
var expr = Mapper.CreateMap<ContactLstModel, ContactLstModel>().ForMember("ContactType", (conf) => { conf.Ignore(); });
var merged = Mapper.Map<ContactLstModel, ContactLstModel>(_Contact, _ContactOption);
With Automapper you can control how to map each single property from source to destination.
If you don't want external library dependencies, and want full control you can use a pure Reflection approach.
For example you could use something similar as the CopyValues method from this link and merge the second object properties with the first one using reflection.
CopyValues<ContactLstModel>(_Contact, _ContactOption);
So this line of code will copy the ContactType property values from the second object into the first one.
CopyValues uses reflection to loop through the properties of the objects:
public static void CopyValues<T>(T target, T source)
{
Type t = typeof(T);
var properties = t.GetProperties().Where(prop => prop.CanRead && prop.CanWrite);
foreach (var prop in properties)
{
var value = prop.GetValue(source, null);
if (value != null)
prop.SetValue(target, value, null);
}
}
Of course this does not support everything jquery extend does (merging, shallow and deep cloning into a new object etc.), but it can satisfy your current needs. You can extend on these principles and build a more comprehensive solution.
However have in mind that C# is not a language like Javascript, and the cost of doing reflection is much higher in C#, while in Javascript the properties of a prototype can be listed with a cheap for-in iteration, or with a call to Object.keys().
You could do it with an extension method:
public static class ContactModelExtensions {
public static ContactModel Extend(this ContactModel first, ContactModel replacement) {
if (!replacement.ContactsName.IsNullOrEmpty()) // or whatever criteria you want
{
first.ContactsName = replacement.ContactsName;
}
// similar assignment for all other properties
return first; // since we return the first one, properties not set in override
// will be untouched
}
}
Now, you can just
var extendedContact = _Contact.Extend(_ContactOptions);
to get it done.
You can use some frameworks for do it. For example with ValueInjecter:
public class NoNullsInjection : ConventionInjection
{
protected override bool Match(ConventionInfo c)
{
return c.SourceProp.Name == c.TargetProp.Name
&& c.SourceProp.Value != null;
}
}
class A
{
public string a { get; set; }
public string b { get; set; }
}
static void Main(string[] args)
{
A a1 = new A() { a = "123" };
A a2 = new A() { b = "456" };
A c = new A();
c.InjectFrom(new NoNullsInjection(),a1,a2);
// "c" now have a="123", b="456"
}
I have a an object called FooObject:
public class FooObject
{
public string Test1 {get; set;}
public List<FooSubObject> SubTest1 {get; set;}
}
For later in the example, I also have a DifferenceFooObject:
public class DifferenceFooObject
{
public string SharedTest1 { get; set; }
public List<FooSubObject> SubTest1 {get; set;}
}
For later in the example, I also have a FooSubObject. FooObject has a property SubTest1 that contains a typed collection of this type:
public class FooSubObject
{
public string Test2 { get; set; }
}
I have a method that accepts a typed collection of FooObject. In this method, I need to calculate if any of the properties between the FooObjects within the typed collection parameter, have equal properties.
public DifferenceFooObject RunPropComparison(List<FooObject> foos)
{
DifferenceFooObject difference = new DifferencFooObject();
FooObject forComparison = foos.FirstOrDefault();
IEnumerable<FooObject> intersectCollection = foos.Skip(1);
// maybe do this using the first to compare the rest? No clue
}
I do not know the most efficient way to complete the above method. It is further complicated, at least IMHO, that the calculation has to take into account the properties of objects in collections that are a property of FooObject (looping through the properties of FooSubObject).
Here is the requested in/out:
List<FooObject> foos = new List<FooObject>();
FooObject obj = new FooObject();
obj.Test1= "Test1";
obj.SubTest1 = new List<FooSubObject>();
FooSubObject obj2 = new FooSubObject();
obj2.Test2 = "Test2";
obj.SubTest1.Add(obj2);
FooObject obj3 = new FooObject();
obj3.Test1= "Test1";
obj3.SubTest1 = new List<FooSubObject>();
FooSubObject obj4 = new FooSubObject();
obj4.Test2 = "Test3";
obj3.SubTest1.Add(obj2);
That's what would go in, ideally it would return that Test1 is the same across the board.
Best as I can tell, this is what you're looking for:
public IList<DifferenceFooObject> RunPropComparison(List<FooObject> foos)
{
var differences = new List<DifferenceFooObject>();
foreach (var group in foos.GroupBy(x => x.Test1))
{
var difference = new DifferenceFooObject();
difference.SharedTest1 = group.Key;
difference.SubTest1 = group.SelectMany(x => x.SubTest1).ToList();
differences.Add(difference);
}
return differences;
}
Or if you add the following constructor:
public DifferenceFooObject(string sharedTest1, IEnumerable<FooSubObject> subTest1)
{
this.SharedTest1 = sharedTest1;
this.SubTest1 = subTest1.ToList();
}
Then you can make this code shorter:
public IList<DifferenceFooObject> RunPropComparison(List<FooObject> foos)
{
return foos.GroupBy(x => x.Test1)
.Select(g => new DifferenceFooObject(g.Key, g.SelectMany(x => x.SubTest1)))
.ToList();
}
I don't think there is an especially efficient way of doing this. You will need to rely heavily on Reflection using the getProperties method to get at the values of the object properties...
You could look into using FasterFlect (http://fasterflect.codeplex.com/) which has better performance over standard .Net reflection...
Check out this library. It compares two objects and tells you the different properties http://comparenetobjects.codeplex.com/documentation
I have a function, where i could send all objects of all types of my project and it should iterate over properties and output their values:
public void ShowMeAll(IEnumerable<object> items);
IEnumerable<Car> _cars = repository.GetAllCars();
ShowMeAll(_cars);
IEnumerable<House> _houses = repository.GetAllHouses();
ShowMeAll(_houses);
Ok, for example, it's so. Now, i'd like to send into my ShowMeAll function a property, which over i'd like to OrderBy my items and then output. What is the most correct way to do this with a parameter of function?
Easiest way is to let LINQ do that for you, via the OrderBy() method. For example:
IEnumerable<Car> _cars = repository.GetAllCars();
ShowMeAll(_cars.OrderBy(car => car.Make));
IEnumerable<House> _houses = repository.GetAllHouses();
ShowMeAll(_houses.OrderBy(house => house.SquareFootage));
That way, you remove the requirement for ShowMeAll to be aware of the properties of the objects passed in. Since you're passing List<object>, I assume that's desired. :)
private static void ShowMeAll<TClass>(IEnumerable<TClass> items, string property)
{
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(TClass));
PropertyDescriptor targetProperty = properties.Find(property, true);
if (targetProperty == null)
{
// Your own error handling
}
IEnumerable<TClass> sortedItems = items.OrderBy( a => targetProperty.GetValue(a));
// Your own code to display your sortedItems
}
You would call the method like this:
ShowMeAll<Car>(_cars, "Make");
I've left out the error handling because I do not know what your requirements are
private static void ShowMeAll<TClass>(IEnumerable<TClass> items, string property )
{
// 1. Discover property type ONCE using reflection
// 2. Create a dynamic method to access the property in a strongly typed fashion
// 3. Cache the dynamic method for later use
// here, my dynamic method is called dynamicPropertyGetter
IEnumerable<TClass> sortedItems = items.OrderBy( o => dynamicPropertyGetter( o ) );
}
Dynamic methods (easier than they look, and 50-100x faster than reflection in my tests): http://msdn.microsoft.com/en-us/library/exczf7b9.aspx
Expression builders can also get the job done: http://msdn.microsoft.com/en-us/library/system.web.compilation.expressionbuilder.aspx
kind of this?
public void Test()
{
var o = new[] {new {Name = "test", Age = 10}, new {Name = "test2", Age = 5}};
ShowMeAll(o, i => i.Age);
}
public void ShowMeAll<T>(IEnumerable<T> items, Func<T, object> keySelector)
{
items.OrderBy(keySelector)
.ToList()
.ForEach(t => Console.WriteLine(t));
}