Create properties dynamically - c#

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

Related

Is There A Way To Call Class Properties Generically?

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");});
}
}

generate code for xml-serialization

I want to create a class to be serialized. However I want the Order-attribute to be explicitely set on every member within my class. So I wrote this code:
public void Process(CodeNamespace code, XmlSchema schema)
{
var types = code.Types.Cast<CodeTypeDeclaration>().Where(x => !x.IsEnum);
foreach (var type in types)
{
foreach(var member in type.Members.Cast<CodeTypeMember>().Select((x, i) => new { Item = x, Order = i }))
{
member.Item.CustomAttributes.Add(new CodeAttributeDeclaration("XmlElementAttribute", ???);
}
}
}
I don´t know how to set the named argument Order to a valid value. I already tried new[] { Order = member.Order } but apparently this doesn´t work at all.
So what I want is something that creates this code:
public class MyClass
{
[XmlElement("MyProp", Order = 0)]
public int Prop1 { get; set; }
}
The solution is quite simple. I compared the process with XmlElement-attributes that were automatically added and noticed, that the attributes name is not XmlElementAttribute but System.Xml.Serialization.XmlElementAttribute. Furthermore - as the Order-parameter is an argument of the XmlElementAttribute-constructor we have to add it as CodeAttributeArgument:
var attr = new CodeAttributeDeclaration("System.Xml.Serialization.XmlElementAttribute");
attr.Arguments.Add(new CodeAttributeArgument("Order", new CodePrimitiveExpression(member.Order)));
member.Item.CustomAttributes.Add(attr);

Is there a jQuery extend in c#?

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"
}

Return Properties That Are The Same From Typed Collection

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

Cast ExpandoObject to anonymous type

Can I cast ExpandoObject to anonymous type ?
var anoObj = new { name = "testName", email = "testEmail" };
dynamic expandoObj = new System.Dynamic.ExpandoObject();
// Here I'm populating the expandoObj with same property names/types in anonymoustype(anoObj)
// Now, how to convert this ExpandoObject to anonymoustype ?
var newObj = (typeof(anoObj)expandoObj); // This doesn't work
Added Later
// This is my entity
public class Customer
{
#region Public Properties
[ColumnAttribute(Name = "IdColumn")]
public string Id { get; set; }
[ColumnAttribute(Name = "NameColumn")]
public string Name { get; set; }
[ColumnAttribute(Name = "AddressColumn")]
public string Address { get; set; }
[ColumnAttribute(Name = "EmailColumn")]
public string Email { get; set; }
[ColumnAttribute(Name = "MobileColumn")]
public string Mobile { get; set; }
#endregion
}
// -------------------------------------------------------------------------------------
public class LookupService<TEntitySource>
{
public LookupService ()
{
}
public LookupShowable<TEntitySource, TSelection> Select<TSelection>(Expression<Func<TEntitySource, TSelection>> expression)
{
var lookupShowable = new LookupShowable<TEntitySource, TSelection>();
return lookupShowable;
}
}
public class LookupShowable<TEntitySource,TSelection>
{
public LookupShowable()
{
}
public LookupExecutable<TEntitySource, TSelection, TShow> Show<TShow>(Expression<Func<TEntitySource, TShow>> expression)
{
var lookupExecutable = new LookupExecutable<TEntitySource,TSelection,TShow>();
return lookupExecutable;
}
}
public class LookupExecutable<TEntitySource, TSelection, TShow>
{
public TSelection Execute()
{
// Here I want to create a new instance of TSelection and populate values from database and return it.
}
}
//--------------------------------------------------------------------------------------
// This is How I want to call this from front end...
var lookupService = new LookupService<Customer>();
var lookupSelection = lookupService.Select(C => new { C.Id, C.Name, C.Mobile }).Show(C => new { C.Id, C.Name}).Execute();
string sID = lookupSelection.Id;
string sName = lookupSelection.Name;
string sMobile = lookupSelection.Mobile;
Dont think about this middle part.. Purpose of it is another one...
My problem is in Execute() method in LookupExecutable class. I dont know how to create a new instance of TSelection type and assign values to it. This TSelection type is always an anonymous type..
EDIT: I think this question is a prime example of the XY problem. The correct solution doesn't need to concern itself with ExpandoObject or anonymous types, and it would be most likely wrong if it did.
You're looking at it the wrong way. You don't need to create an instance of an anonymous object, you need to invoke the code that is passed to you in an expression (which may or may not be creating an anonymous object).
If you can create an instance of TEntitySource, then that's simple: Compile() the Expression that you got in Select() and then invoke it for each instance of TEntitySource.
If you can't create TEntitySource, you could still do it by rewriting the Expression (using ExpressionVisitor), so that its input is not TEntitySource, but some type you have. But that would require some work from you.
Original answer:
No, that won't work. That's simply not how casting or anonymous types work in C#.
You can't cast between any two types and expect it to work. Either the object you're casting needs to be the type you're casting to, or one of the two types needs to specify a matching cast operator.
The fact that the target type is an anonymous type doesn't change anything (except that you can't even try to cast to an anonymous type directly, because you can't name it; the way you're using typeof() is wrong).
The fact that the source type is dynamic changes things a bit. But only in that the search for the cast operator is done at runtime, not at compile time, and you can even create the cast operator at runtime (see DynamicObject.TryCast()). But that's it, it doesn't add any “magical” cast operators.
The only way I can imagine something like this working would be if you used a variant of “cast by example” and reflection:
public T Convert<T>(ExpandoObject source, T example)
where T : class
{
IDictionary<string, object> dict = source;
var ctor = example.GetType().GetConstructors().Single();
var parameters = ctor.GetParameters();
var parameterValues = parameters.Select(p => dict[p.Name]).ToArray();
return (T)ctor.Invoke(parameterValues);
}
You could then use it something like this:
var expando = new ExpandoObject();
dynamic dynamicExpando = expando;
dynamicExpando.Foo = "SomeString";
dynamicExpando.Bar = 156;
var result = Convert(expando, new { Foo = "", Bar = 1 });
Note that you can't actually invoke Convert() dynamically (by passing it dynamicExpando), because that would mean it would return dynamic too.
Use JavaScriptSerializer to convert the ExpandoObject to any Type as follows:
.....
dynamic myExpandoObject = new ExpandoObject();
var result = ConvertDynamic<myType>(myExpandoObject);
.....
public T ConvertDynamic<T>(IDictionary<string, object> dictionary)
{
var jsSerializer = new System.Web.Script.Serialization.JavaScriptSerializer();
var obj = jsSerializer.ConvertToType<T>(dictionary);
return obj;
}
This should do the job.
here you have an object made from an ExpandoObject
var anoObj = new { name = "testName", email = "testEmail" };
dynamic expandoObj = new System.Dynamic.ExpandoObject();
object newObj = expandoObj;
But beware, dynamic objects are very very expensive in resource matters, and what you are asking for does not seem to have any sense. A good aproach for what you are asking in the comments supposing you have to deal with dynamic objects and you want to do something with them:
dynamic expando = new System.Dynamic.ExpandoObject();
var myObj = new Dictionary<string, object>();
myObj["myProperty"] = expando.myProperty;
Any dynamyc object is easily casted to a <string, object> typed Dicionary.
Hope that helps!

Categories

Resources