Dynamically Create C# Class or Object - c#

I have this structure.
public class FirstClass
{
public List<Foo> FooList{ get; set; }
}
public class Foo{
//Ex:
//public string Name{ get; set; }
}
public List<Foo> GetFoo(){
//I'm use Firstclass like this here typeof(FirstClass);
//I want create here dynamic property for Foo class.
}
And my problem is, i want create property for "Foo" class from "GetFoo()" function. Same time, this function return "List" "Foo" type. I'm research "Dynamically Add C# Properties at Runtime", "How to dynamically create a class in C#?" but the answers in these links are not referenced as return values or referenced to another class. How i can do this?

You can dynamically create classes, which inherits Foo, with any additional properties. Thus you can add instances of those dynamic classes into List<Foo>.
To do so, one can generate a code string like following:
var bar1Code = #"
public class Bar1 : Foo
{
public Bar1(int value)
{
NewProperty = value;
}
public int NewProperty {get; set; }
}
";
Then compile it using CSharpCodeProvider:
var compilerResults = new CSharpCodeProvider()
.CompileAssemblyFromSource(
new CompilerParameters
{
GenerateInMemory = true,
ReferencedAssemblies =
{
"System.dll",
Assembly.GetExecutingAssembly().Location
}
},
bar1Code);
Then one can create an instance of Bar1, add it to List<Foo> and, e.g. cast it to dynamic to access the dynamic property:
var bar1Type = compilerResults.CompiledAssembly.GetType("Bar1");
var bar2Type = compilerResults.CompiledAssembly.GetType("Bar2"); // By analogy
var firstClass = new FirstClass
{
FooList = new List<Foo>
{
(Foo)Activator.CreateInstance(bar1Type, 56),
(Foo)Activator.CreateInstance(bar2Type, ...)
}
};
var dynamicFoo = (dynamic)firstClass.FooList[0];
int i = dynamicFoo.NewProperty; // should be 56

Why don't you just use a Dictionary;
public class Foo
{
public Dictionary<string, object> Properties;
public Foo()
{
Properties = new Dictionary<string, object>();
}
}
public List<Foo> GetFoo()
{
var item = new Foo();
item.Properties.Add("Name","Sample");
item.Properties.Add("OtherName", "Sample");
return new List<Foo>{ item };
}
Adding property for a class in runtime, it is not possible to perform.

Related

Base Class Serialization Issue - do not serialize Derived Class Properties

I am tiring to serialize a fairly large list of entities, that are all derived from a base class.
I only need the base class properties in the client. How do I achieve this without instantiating a new instance of the base class?
I have tried creating a custom ContractResolver, but it seems that it does a getType() at runtime, instead of using the Type of the list/Array being serialized
See code sample below.
I want to achieve. castBaseString == actualBaseString ;
So I want castBaseString to = [{"Id":1},{"Id":2}] not [{"Value":"value","Id":1},{"Value":"value2","Id":2}]
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Collections.Generic;
using Newtonsoft.Json;
namespace Tests {
[TestClass]
public class JsonNetTest {
class Base {
public int Id { get; set; }
}
class Derived : Base {
public string Value { get; set; }
}
class OtherDerived : Base {
public string Value { get; set; }
public string OtherValue { get; set; }
}
[TestMethod]
public void Test() {
IEnumerable<Derived> deriveds = new Derived[] {
new Derived {Id = 1, Value = "value" },
new Derived {Id = 2, Value = "value2" }
};
IEnumerable<Base> castBases = deriveds.Cast<Base>().ToList();
IEnumerable<Base> bases = new Base[] {
new Base {Id = 1 },
new Base {Id = 2 }
};
JsonSerializerSettings s = new JsonSerializerSettings();
var derString = JsonConvert.SerializeObject(deriveds, s);
var castBaseString = JsonConvert.SerializeObject(castBases, s);
var actualBaseString = JsonConvert.SerializeObject(bases, s);
Assert.AreEqual(actualBaseString, castBaseString);
Assert.AreNotEqual(castBaseString, derString);
}
}
}
EDIT BASED ON COMMENTS
Additional Context:
I just posted this simple test case for clarity.
the actual context this is being used is in an aspnet core application.
Consider there are 3 controllers
/api/DerivedController/
/api/OtherDerivedController/
/api/BaseController/
when a client calls 1, we want to return a list of Derived, when a client calls
2 we want to return a list of OtherDerived when they call 3, we want to return a list of Base
The data is stored in 2 different tables in the database TBL_DERIVED and TBL_OTHERDERIVED.
What we want to achieve when they call base is to return data from One or both of these tables, but just the common properties of these tables.
Hope this clarifies.
If you don't want to use attributes, you can use a ContractResolver to force only properties from Base to be serialized:
public class DerivedTypeFilterContractResolver<T> : DefaultContractResolver {
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) {
JsonProperty property = base.CreateProperty(member, memberSerialization);
if (property.DeclaringType != typeof(T)) {
property.ShouldSerialize = instance => false;
}
return property;
}
}
Then use it like this:
void Main() {
IEnumerable<Derived> deriveds = new Derived[] {
new Derived {Id = 1, Value = "value" },
new Derived {Id = 2, Value = "value2" }
};
IEnumerable<Base> castBases = deriveds.Cast<Base>().ToList();
IEnumerable<Base> bases = new Base[] {
new Base {Id = 1 },
new Base {Id = 2 }
};
JsonSerializerSettings s = new JsonSerializerSettings {
ContractResolver = new DerivedTypeFilterContractResolver<Base>()
};
var derString = JsonConvert.SerializeObject(deriveds, s);
var castBaseString = JsonConvert.SerializeObject(castBases, s);
var actualBaseString = JsonConvert.SerializeObject(bases, s);
Console.WriteLine(castBaseString);
}
class Base {
public int Id { get; set; }
}
class Derived : Base {
public string Value { get; set; }
}
Output:
[{"Id":1},{"Id":2}]
Add [JsonIgnore] top of property.
class Derived : Base {
[JsonIgnore]
public string Value { get; set; }
}
Turns out this is not possible the way the json serialization works.
#stuartd answer might be a good workaround if you only have limited cases you want to do this for.

How to get type of objects in an empty list of an interface

Consider:
public interface I
{
int InterfaceProperty {get;set;}
}
public class C1 : I
{
public int InterfaceProperty {get;set;}
public int Class1Property {get;set;}
}
public class C2 : I
{
public int InterfaceProperty {get;set;}
public int Class2Property {get;set;}
}
//In some other class:
public List<I> L;
void somemethod()
{
this.L = new List<I>();
this.L.Add(new C1()); //add some C1s into the list
SomeMethodToGetProperties(L);
this.L = new List<I>();
this.L.Add(new C2()); //add some C2s into the list
SomeMethodToGetProperties(L);
}
I need SomeMethodToGetProperties that gets a list of the properties for C1 or C2. ie, first call returns InterfaceProperty and Class1Property and the second call returns InterfaceProperty and Class2Property.
I can't use an object in the list, because the lists may be empty. I tried Reflection on the lists, but that only gave me the properties for the interface.
EDIT: The original way I wrote it was not valid. You can't do
this.L = new List<C1>()
You can only do something like
this.L = new List<I>();
this.L.Add(new C1());
It seems what I need may not be possible from the metadata of the list itself.
So I created a second variable to hold the type of item held in the list that I set every time I change the list contents.
This is one implementation, that scans each item in a list, and collects the item type and its properties. This is because each list might have more than one type that is inherited from the interface.
I renamed the interface and classes for clarity.
The result is
Class1
InterfaceProperty
Class1Property
Class2
InterfaceProperty
Class2Property
with code:
public interface IInterface
{
int InterfaceProperty { get; set; }
}
public class Class1 : IInterface
{
public int InterfaceProperty { get; set; }
public int Class1Property { get; set; }
}
public class Class2 : IInterface
{
public int InterfaceProperty { get; set; }
public int Class2Property { get; set; }
}
class Program
{
public static List<IInterface> list;
static void Main(string[] args)
{
list = new List<IInterface>();
list.Add(new Class1());
list.Add(new Class2());
list.Add(new Class1());
list.Add(new Class1());
list.Add(new Class2());
foreach (var itemType in GetItemTypeProperties(list))
{
Console.WriteLine(itemType.Key.Name);
foreach (var property in itemType.Single())
{
Console.WriteLine($"\t{property.Name}");
}
Console.WriteLine();
}
}
public static IEnumerable<IGrouping<Type,PropertyInfo[]>> GetItemTypeProperties<T>(List<T> list)
{
var itemProperties = new Dictionary<Type, PropertyInfo[]>();
foreach (var item in list)
{
var t = item.GetType();
if (!itemProperties.ContainsKey(t))
{
itemProperties[t] = t.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
}
}
return itemProperties.GroupBy(kv => kv.Key, kv=>kv.Value);
}
}
You can also get the same result, by scanning only the first item in the list and assuming the remaining items are of the same time. This time, like in your question, I re-assign the list with a new set of items of a different type.
This produces the following result:
Class1
InterfaceProperty
Class1Property
Class2
InterfaceProperty
Class2Property
from the code:
list = new List<IInterface>();
list.Add(new Class1());
list.Add(new Class1());
list.Add(new Class1());
var item1 = list.First();
var properties1 = item1.GetType().GetProperties();
Console.WriteLine($"{item1.GetType().Name}");
foreach (var prop in properties1)
{
Console.WriteLine($"\t{prop.Name}");
}
list = new List<IInterface>();
list.Add(new Class2());
list.Add(new Class2());
var item2 = list.First();
var properties2 = item2.GetType().GetProperties();
Console.WriteLine($"{item2.GetType().Name}");
foreach (var prop in properties2)
{
Console.WriteLine($"\t{prop.Name}");
}
To get the actual type of the list:
Type listType = this.L.GetType();
To get the types of objects it can contain:
Type elementType = listType.GetGenericArguments().Single();
To get the properties for that type:
var properties = elementType.GetProperties();

Add or AddRange to List in C# Initialize Object

As explained in https://learn.microsoft.com/de-de/visualstudio/code-quality/ca2227?view=vs-2019 I've got an object with a read only list like this:
public class MyClass {
public int id { get; set; }
public List<string> stringList { get; } = new List<string>;
}
But how can I initialize MyClass by adding data to stringList?
MyClass test = new MyClass(){
id = 1,
stringList = ???
}
You can use not very obvious syntax with collection initializers:
var x = new MyClass
{
id = 1,
stringList = {"as", "ddsd"} // will ADD "as", "ddsd" to stringList
};
Console.WriteLine(string.Join(", ", x.stringList)); // prints as, ddsd
Bur usual approach to handle readonly properties (until C# 9 is released with init only properties and records) is to pass initialization values in constructor.
You can pass the stringList as a parameter in the constructor and assign the property to the parameter:
public class MyClass {
public int id { get; set; }
public List<string> stringList { get; } = new List<string>();
public MyClass(List<string> stringList) {
this.stringList = stringList;
}
}

Deserialize JSON into dynamic class

I need to deserialize a JSON string into a type which is not know at compile time. There are several classes that it can be deserialized into. The name of the class is provided as input into the application and based on that I want to instantiate the class (already done this through reflection):
var type = Type.GetType(className);
var myClassInstance = (IParser)Activator.CreateInstance(type);
...and then use its type as the generic type parameter for JsonConvert.DeserializeObject<typeof(myClassInstance).Name>(jsonString) but that doesn't work.
How can I provide the class to DeserializeObject<>() dynamically?
Instead of using an generic method overload like JsonConvert.DeserializeObject<T>(String) and having to resort to reflection as some comments state, you could simply use the non generic counterpart JsonConvert.DeserializeObject(String, Type), which just takes in a Type instance like you already have!
Implementation
Initialization
var class1s = new Class1() {
ID = 1, Name = "Test", Comment = "This Code is Tested!."
};
var class2s = new Class2() {
xVal1 = 1, XVal2 = 5, xval3 = 10
};
var JSON1 = Newtonsoft.Json.JsonConvert.SerializeObject(class1s);
var JSON2 = Newtonsoft.Json.JsonConvert.SerializeObject(class2s);
Calling Functions
var classname1 = typeof(Class1).FullName;
var type1 = Type.GetType(classname1);
var classname2 = typeof(Class2).FullName;
var type2 = Type.GetType(classname2);
var c = LocalConverter(JSON1, type1);
var c2 = LocalConverter(JSON2, type2);
Class Models
public class Class1 {
public int ID {
get;
set;
}
public string Name {
get;
set;
}
public string Comment {
get;
set;
}
}
public class Class2 {
public int xVal1 {
get;
set;
}
public int XVal2 {
get;
set;
}
public int xval3 {
get;
set;
}
}
Required Method
private object LocalConverter(string o, Type xtype) {
return Newtonsoft.Json.JsonConvert.DeserializeObject(o, xtype);
}

How can I compare two lists with xunit test

I am currently trying to compare two lists, with the same items in it, with xUnit but getting an error while running.
Assert.Equal(expectedList, actualList);
Error:
"Assert.Equal() Failure"
Expected: List<myObject> [myObject { modifier = '+', name = "name", type = "string" }, myObject { modifier = '+', name = "age", type = "int" }]
Actual: List<myObject> [myObject { modifier = '+', name = "name", type = "string" }, myObject { modifier = '+', name = "age", type = "int" }]
This has to do with object equality.
MyObject does not implement the Equals method. By default you get a reference equality. I assume you have two different objects for MyObject.
Meaning it does not matter that your List holds the similar object(meaning with same values) they are not of the same reference, so your test checks that, this is why it fails.
internal class MyObject
{
{
public char Modifier { get; set; }
public string Name { get; set; }
public string Type { get; set; }
}
}
[Fact]
public void ListMyObject()
{
var list1 = new List<MyObject>
{
new MyObject{ }
};
var list2 = new List<MyObject>
{
new MyObject{ }
};
Assert.Equal(list1, list2); // Fails
}
When we update our class to this.
internal class MyObject
{
public char Modifier { get; set; }
public string Name { get; set; }
public string Type { get; set; }
//When i add this to my class.
public override bool Equals(object obj)
{
return this.Name == ((MyObject)obj).Name;
}
}
Also as mentioned in the comments by Jonathon Chase.
It is a good idea to override the GetHashCode() method as well. It is preferred to inherit from IEquatable<T> so you can avoid casting.
Everything goes green.
[Fact]
public void ListMyObject()
{
var list1 = new List<MyObject>
{
new MyObject{ Name = "H" }
};
var list2 = new List<MyObject>
{
new MyObject{ Name = "H" }
};
Assert.Equal(list1, list2); //Passes
}

Categories

Resources