I have 2 different child classes. The main reason is cos the database fields are different from the one going into the Gui. So they both have common parent class.
Class DbChild1 : Parent1
{ ....
}
Class GuiChild1 : Parent1
{....
}
I have a IEnumerable resultset of the DbChild1. I am trying to use Linq to copy the data over. But since there are really lots of properties and I am doing this in more than one place for other similar DBclass and Gui class, I am wondering if there is any shortcut way to copy over the common parent properties instead of copying one by one.
Thanks for all your help in advance.
Cheers
In case you haven't checked AutoMapper you can try this:
class Program
{
static void Main(string[] args)
{
var dbChild1ResultSet = new[]
{
new DbChild1()
{
Field1 = "1",
Field2 = "2",
DbChild1Field1 = "3"
},
new DbChild1()
{
Field1 = "11",
Field2 = "22",
DbChild1Field1 = "33"
},
};
var guiChild1ResultSet = dbChild1ResultSet.Select(x => new GuiChild1(x)
{
GuiChild1Field1 = x.DbChild1Field1
});
}
}
public class Parent1
{
public string Field1 { get; set; }
public string Field2 { get; set; }
public Parent1()
{
}
public Parent1(Parent1 toCopyFrom)
{
Field1 = toCopyFrom.Field1;
Field2 = toCopyFrom.Field2;
}
}
public class DbChild1 : Parent1
{
public string DbChild1Field1 { get; set; }
public DbChild1()
{
}
public DbChild1(Parent1 toCopyFrom) : base(toCopyFrom)
{
}
}
public class GuiChild1 : Parent1
{
public string GuiChild1Field1 { get; set; }
public GuiChild1()
{
}
public GuiChild1(Parent1 toCopyFrom) : base(toCopyFrom)
{
}
}
Related
I have these classes
public class SubMenuItem : SubMenuVariant
{
public string SubMenuTitle { get; set; }
public LinkFieldType Link { get; set; }
public List<SubMenuSubItem> SubItems { get; set; }
}
public class SubMenuHighlightItem : SubMenuVariant
{
[JsonPropertyName(FieldNames.HighlightTitle)]
public string HighlightTitle { get; set; }
[JsonPropertyName(FieldNames.HighlightText)]
public string HighlightText { get; set; }
[JsonPropertyName(FieldNames.HighlightText)]
public Link HighLightLink { get; set; }
}
public class SubMenuVariant
{
}
Which I currently store in a List<SubMenuVariant> submenu
Problem is though I am not able to access the individual properties the different menues have, since they are being casted to a SubMenuVariant, which don't have any properties.
The list can only contain one type, at no point will both types exist in the list. The items is not being added explicitly to the list, but is being created by JsonSerializer.Deserialize a json request, which contains the properties, to the baseclass.
So the json can either look like this:
{
"submenu": [
{
"SubMenuTitle " : "Title",
"Link" : "Link",
"SubItems" : [
{...}
]
}
]
}
Or
{
"submenu": [
{
"HighlightTitle " : "Title",
"HighlightLink" : "Link",
"HighlightText" : "Text"
}
]
}
Is it somehow possible to store different class types in the same list?
Your issue is not that you can't store different types derived from the same base class. Your problem is accessing the members of the run-time types of the objects. That requires a cast. You can conditionally cast the items as you get them out of the list:
foreach (var smv in submenu)
{
var smi = smv as SubMenuItem;
if (smi != null)
{
// ...
}
else
{
var smhi = smv as SubMenuHighlightItem;
if (smhi != null)
{
// ...
}
}
}
In newer versions of C#, you can use pattern-matching:
foreach (var smv in submenu)
{
if (smv is SubMenuItem smi)
{
// ...
}
else if (smv is SubMenuHighlightItem smhi)
{
// ...
}
}
Here's an example of the pattern-matching option in action:
class Program
{
static void Main(string[] args)
{
var items = new List<BaseType>();
items.Add(new FirstDerivedType { FirstName = "One" });
items.Add(new SecondDerivedType { SecondName = "Two" });
items.Add(new FirstDerivedType { FirstName = "Three" });
items.Add(new SecondDerivedType { SecondName = "Four" });
foreach (var bt in items)
{
if (bt is FirstDerivedType fdt)
{
Console.WriteLine(fdt.FirstName);
}
else if (bt is SecondDerivedType sdt)
{
Console.WriteLine(sdt.SecondName);
}
}
}
}
public class FirstDerivedType : BaseType
{
public string FirstName { get; set; }
}
public class SecondDerivedType : BaseType
{
public string SecondName { get; set; }
}
public class BaseType
{
}
No, your solution is as good as it gets. The only other - worse - option being List<object>.
You can also try reflection, if you know the property name you can
access it as follows:
internal class Program
{
static void Main(string[] args)
{
List<SubMenuVariant> variants = new List<SubMenuVariant>();
variants.Add(new Sub1() { Title = "Test" });
variants.Add(new Sub2());
var prop = variants.First().GetType().GetProperty("Title");
prop?.GetValue(variants.First(), null);
}
}
public class Sub1 :SubMenuVariant
{
public string Title { get; set; }
}
public class Sub2: SubMenuVariant
{
public int Index { get; set; }
}
public class SubMenuVariant
{
}
This will generate the following result:
sorry for my bad english. But i need a little help with this method (ToObject)
I have this class
namespace Proyects
{
public class AProductType
{
public DateTime CreationDate { get; set; }
public string Product { get; set; }
}
public class AProduct
{
public AProductType A_ProductType { get; set; }
}
public class AProductPlantType
{
public string SerialNumberProfile { get; set; }
}
public class ToPlant
{
public List<AProductPlantType> A_ProductPlantType { get; set; }
}
public class AProductDescriptionType
{
public string Language { get; set; }
public string Product { get; set; }
public string ProductDescription { get; set; }
}
public class ToDescription
{
public List<AProductDescriptionType> A_ProductDescriptionType { get; set; }
}
public class Root
{
public AProduct A_Product { get; set; }
public ToPlant to_Plant { get; set; }
public ToDescription to_Description { get; set; }
}
}
I am currently using the Root one to save a Jtoken in there. But i cant save the data on the propieties from Root class.
For example:
var object= myJson.ToObject<Root>();
If i try to save data on the propiety Product from AProductType, i cant access there using using ToOject. I try someting like this
var object= myJson.ToObject<Root>().A_Product.A_ProductType.Product;
And dont work, object var become null. I need some way to save the data around this complex object saving then in the propietes from Root.
Really sorry for my english, Thanks!!!
Edit: Json file
{
"A_Product": {
"A_ProductType": {
"CreationDate": "2020-01-17T00:00:00",
"Product": "158"
}
},
"to_Plant": {
"A_ProductPlantType": [
{
"SerialNumberProfile": "E001"
}
]
},
"to_Description": {
"A_ProductDescriptionType": [
{
"Language": "EN",
"Product": "158",
"ProductDescription": "Terminal LaP (nro de serie + equipo)"
},
{
"Language": "ES",
"Product": "158",
"ProductDescription": "Terminal LaP"
}
]
}
}
Edit 2:
private static List<string> retrieveData(JObject ob, List<Root> listaObjetos)
{
List<string> ListaCodigoProducto = new List<string>();
Root objetoRot = new Root();
var A_Product = ob["A_Product"];
if (A_Product.HasValues)
{
var validacion = ob["A_Product"]["A_ProductType"];
if (validacion.Type == JTokenType.Object)
{
var objeto = validacion.ToObject<AProductType>();
ListaCodigoProducto.Add(objeto.Product);
objetoRot.A_Product.A_ProductType.Product = objeto.Product;
listaObjetos.Add(objetoRot);
}
When i try to save the product number on
objetoRot.A_Product.A_ProductType.Product
It shows NullReference exception, i cant access to the propiety in the Root object
The deserializing code is working just fine. Your problem is that you're accessing objects that aren't there.
When you say Root objetoRot = new Root();, you are creating a new, empty Root. Its A_Product value will be null. A few lines down, you are saying objetoRot.A_Product.A_ProductType.Product = objeto.Product;. But you can't get objetoRot.A_Product.A_ProductType because there is no objetoRot.A_Product to access properties on.
I have the following code, when I declare MyItem, it will be automatically added into Roster.
public class MyItem
{
private static Dictionary<string, string> Roster;
public static bool addToRoster(MyItem item)
{
if (Roster.ContainsKey(item.code))
return false;
Roster.Add(item.code, item.description);
return true;
}
public string code { get; protected set; }
public string description { get; protected set; }
public MyItem(string _code, string _desc)
{
code = _code;
description = _desc;
addToRoster(this);
}
}
So when I use it like below, Roster dictionary will contain 2 values:
MyItem itema = new MyItem("code1", "desc1");
MyItem itemb = new MyItem("code2", "desc2");
MyItem itemc = new MyItem("code1", "desc1");
So far so good. Now I may have multiple Rosters, based on different type. For example, I may have a Subject, a Room and a Building. I don't want to declare multiple classes derived from MyItem class, that will be too many. Of course I can add a property
string RosterType { get; set; }
in MyItem class, but that will make bunch of data redundancy.
I am thinking maybe I can use attribute, but it seems attribute cannot be used on object.
I am trying to find something like this
[RosterType("Room")]
MyItem item1("WJ203", "Room WJ203");
[RosterType("Subject")]
MyItem item2("MATH01", "Basic Math");
and, change the Roster to be
private static Dictionary<string, Dictionary<string, string>> Rosters;
Then I can add the items into different rosters based on different RosterType. But, it seems I cannot set attribute on object.
What should I do to archive my goal? Any good thought?
Let me add some details
The data I received is like:
{
result: [
{
"propA": { "code":"XXX", "desc":"XXX" },
"propB": { "code":"XXX", "desc":"XXX" },
"propC": { "code":"XXX", "desc":"XXX" }
},
{
"propA": { "code":"XXX", "desc":"XXX" },
"propB": { "code":"XXX", "desc":"XXX" },
"propC": { "code":"XXX", "desc":"XXX" }
},
{
"propA": { "code":"XXX", "desc":"XXX" },
"propB": { "code":"XXX", "desc":"XXX" },
"propC": { "code":"XXX", "desc":"XXX" }
}]
}
There are many different type of result, and most of them are combination of different type of props. all the props are in cod - desc format. I know it is a poor design, but nothing I can do from my side. I need to save the result into different tables, with just code; and also need to save all the code into different code tables. All these need to be done during desearlization. so I am hopping to do this in MyItem class. The categorize procedure maybe happen in OnDesearlization. So for the result part, I can easily customize my class based on different type of result.
The idea is, set the attribute to properties. Have a ResultBase class, which will go over the attributes, and if a Roster Item found, deal with it. So Once all this are done, I just need to declare my different Results with no extra coding...
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Reflection;
namespace RosterNS
{
using IRoster = IDictionary<string, string>;
[DataContract]
public class RosterItem
{
[DataMember]
public string code { get; set; }
[DataMember]
public string description { get; set; }
}
public class Rosters
{
static private Dictionary<string, IRoster> rosters = new Dictionary<string, IRoster>();
public static IRoster RegisterRoster(string category)
{
IRoster roster;
if (!rosters.TryGetValue(category, out roster))
{
roster = new Dictionary<string, string>();
rosters.Add(category, roster);
}
return roster;
}
#if DEBUG
public static void ListRosters()
{
foreach(KeyValuePair<string, IRoster> kvp in rosters)
{
Console.WriteLine("Category:{0}", kvp.Key.ToString());
foreach (KeyValuePair<string, string> skvp in kvp.Value)
Console.WriteLine("\t{0:20}==>{1}", skvp.Key, skvp.Value);
}
}
#endif
}
[AttributeUsage(AttributeTargets.Property)]
public class RosterCategoryAttribute : Attribute
{
private IRoster roster;
public string Category { get; protected set; }
public RosterCategoryAttribute(string category)
{
Category = category;
roster = Rosters.RegisterRoster(category);
}
public void addToRoster(RosterItem item)
{
if (item != null && !roster.ContainsKey(item.code))
roster.Add(item.code, item.description);
}
}
[DataContract]
public class RosterResult
{
//The only implementation that save the RosterItem into categorized Roster
[OnDeserialized]
public void OnDeserialized(StreamingContext sc)
{
PropertyInfo[] properties = GetType().GetProperties();
foreach (PropertyInfo info in properties)
{
RosterCategoryAttribute attr = info.GetCustomAttribute<RosterCategoryAttribute>();
if (attr != null)
attr.addToRoster(info.GetValue(this) as RosterItem);
}
}
}
}
To use it, I need to declare my Result like so
namespace MyResult
{
[DataContract]
public class ResultType1 : RosterResult
{
[DataMember]
[RosterCategory("Location")]
public RosterItem location { get; protected set; }
[DataMember]
[RosterCategory("Status")]
public RosterItem status { get; protected set; }
}
[DataContract]
public class ResultType2 : RosterResult
{
[DataMember]
[RosterCategory("Location")]
public RosterItem location { get; protected set; }
[DataMember]
[RosterCategory("Equipment")]
public RosterItem equipment { get; protected set; }
[DataMember]
public string Name { get; protected set; }
}
}
So after bunch of deserialization, the Roster will be filled up with unique code-spec pair, based on different categories.
Using GraphQL for .NET, I would like to replace the collection of Foo with a new collection.
Given this server-side code:
public class Foo
{
public Foo(string name)
{
Name = name;
}
public string Name { get; set; }
}
public class Root
{
public Foo[] Foos { get; private set; }
public Foo[] UpdateFoos(Foo[] foos)
{
Foos = foos;
return Foos;
}
}
public class MutationSchema : Schema
{
public MutationSchema()
{
Query = new MutationQuery();
Mutation = new MutationChange();
}
}
public class FooType : ObjectGraphType
{
public FooType()
{
Name = "IndividualFoo";
Field<StringGraphType>("name");
}
}
public class FoosType : ObjectGraphType<ListGraphType<FooType>>
{
public FoosType()
{
Name = "ListOfFoo";
Field<ListGraphType<FooType>>("foos");
}
}
public class FoosInput : InputObjectGraphType
{
public FoosInput()
{
Name = "InputForManyFoo";
Field<ListGraphType<FooInput>>("foos");
Field<ListGraphType<FooType>>("foosResult");
}
}
public class FooInput : InputObjectGraphType
{
public FooInput()
{
Name = "InputForSingleFoo";
Field<StringGraphType>("name");
}
}
public class MutationQuery : ObjectGraphType
{
public MutationQuery()
{
Name = "Query";
Field<FoosType>("queryAllFoos");
}
}
public class MutationChange : ObjectGraphType
{
public MutationChange()
{
Name = "Mutation";
Field<FoosInput>(
"updateAllFoos",
arguments: new QueryArguments(
new QueryArgument<FoosInput>
{
Name = "updateFoosQueryArgument"
}
),
resolve: context =>
{
var root = context.Source as Root;
var change = context.GetArgument<Foo[]>("updateFoosQueryArgument");
// TODO: update collection e.g. return root.UpdateFoos(change);
return change;
}
);
}
}
When I run the mutation query:
mutation M {
fooCollection: updateAllFoos(updateFoosQueryArgument: {
foos: [
{name: "First Foo"},
{name: "Second Foo"}
]}) {
foosResult
}
}
Then I get the following error:
{GraphQL.Validation.ValidationError: Cannot query field "foosResult" on type "InputForManyFoo". Did you mean "foosResult"?}
I'm using the latest version of GraphQL for .NET at the time of writing.
What am I missing?
Working Example: How to mutate a list of custom objects in GraphQL for .NET
My answer from Gitter.
Make an ObjectGraphType for the result. Notice that the “shape” of the object that is returned from resolve matches the “shape” of the graph type.
public class FoosResultType : ObjectGraphType
{
public FoosResultType()
{
Field<ListGraphType<FooType>>("foosResult");
}
}
public class FoosResult
{
public IEnumerable<Foo> FoosResult { get;set; }
}
public class MutationChange : ObjectGraphType
{
public MutationChange()
{
Name = "Mutation";
Field<FoosResultType>(
"updateAllFoos",
arguments: new QueryArguments(
new QueryArgument<ListGraphType<FooInput>>
{
Name = "updateFoosQueryArgument"
}
),
resolve: context =>
{
var root = context.Source as Root;
var change = context.GetArgument<List<Foo>>("updateFoosQueryArgument");
// TODO: update collection e.g. return root.UpdateFoos(change);
return new FoosResult { FoosResult = change };
}
);
}
}
And updated mutation:
mutation M {
fooCollection: updateAllFoos(updateFoosQueryArgument: [
{name: "First Foo"},
{name: "Second Foo"}
]) {
foosResult {
name
}
}
}
I am attempting to use ProtoBuf net to serialize an object tree with the classes in the following format:
[ProtoContract]
class MySpecialCollectionList<T> : List<MySpecialCollection<T>>
{
[ProtoMember(1)]
public string Name { get; set; }
}
[ProtoContract]
class MySpecialCollection<T> : List<Special<T>>
{
[ProtoMember(1)]
public string Name { get; set; }
}
[ProtoContract]
class Special<T>
{
[ProtoMember(1)]
public string Name { get; set; }
[ProtoMember(2)]
public string Description { get; set; }
[ProtoMember(3)]
private readonly T _source;
T Source { get { return _source; } }
private Special()
{
}
public Special(T source)
{
_source = source;
}
}
interface IBeast
{
string Name { get; set; }
}
[ProtoContract]
class Ant : IBeast
{
[ProtoMember(1)]
public string Name { get; set; }
}
[ProtoContract]
class Cat : IBeast
{
[ProtoMember(1)]
public string Name { get; set; }
}
[ProtoContract]
class Dog : IBeast
{
[ProtoMember(1)]
public string Name { get; set; }
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
MySpecialCollectionList<IBeast> collectionList = GetSpecialCollectionList();
using (var fs = File.Create(#"c:\temp\protobuftest.bin"))
{
Serializer.Serialize(fs, collectionList);
fs.Close();
}
}
private MySpecialCollectionList<IBeast> GetSpecialCollectionList()
{
var ant = new Ant() { Name = "Mr Ant" };
var cat = new Cat() { Name = "Mr Cat" };
var dog = new Dog() { Name = "Mr Dog" };
var Special = new Special<IBeast>(ant);
var specialCollection1 = new MySpecialCollection<IBeast>() {
{new Special<IBeast>(ant)},
{new Special<IBeast>(cat)},
{new Special<IBeast>(dog)}
};
specialCollection1.Name = "Special Collection1";
var specialCollection2 = new MySpecialCollection<IBeast>() {
{new Special<IBeast>(ant)},
{new Special<IBeast>(dog)}
};
specialCollection2.Name = "Special Collection2";
var specialCollectionList = new MySpecialCollectionList<IBeast>() {
specialCollection1, specialCollection2 };
specialCollectionList.Name = "Special Collection List";
return specialCollectionList;
}
}
Notice how the class I am serializing (MySpecialCollectionList<T>) is derived from a List<SomeOtherClass<T>>, not just List<T>.
I am struggling to work out where to put "ProtoInclude" attributes to get this to serialize all the items in the MySpecialCollectionList. Any help would be much appreciated.
Inheritance is not an issue here since even if A : B it is not true that Foo<A> : Foo<B>. Note that protobuf-net won't use a non-default constructor, although it is possible to skip the constructor, binding to the field directly (even readonly). While you may have 6 T, I can't see (from the code) that it would ever be in doubt which closed type you intend, and if the closed type is known you should be set.
If you have a Foo<SomeBaseClass> and a number of concrete types inherited from SomeBaseClass then the markers would o on SomeBaseClass.
However, if you have a concrete scenario I can use to reproduce your issue, I'll happily take a look.
Updated re edit:
There are a couple of key points drawn out in the example:
in common with most binding APIs, XmlSerializer and IIRC DataContractSerializer, an item is either a list xor an item with values; if a collection (something implementing IList) has properties itself, they will not be serialized; encapsulation is preferred over inheritance here, i.e. something that has a Name and has a list (rather than has a Name and is a list)
protobuf-net v1 does not support interface-based serialization; v2 does, but as with XmlSerializer and DataContractSerializer you need to explicitly tell it what things it needs to expect; quite nicely, though, we can move the [ProtoMember] onto the interface itself
Here's a fully working version in v2:
using System.Collections.Generic;
using ProtoBuf;
[ProtoContract]
class MySpecialCollectionList<T>
{
[ProtoMember(1)]
public string Name { get; set; }
private readonly List<MySpecialCollection<T>> items = new List<MySpecialCollection<T>>();
[ProtoMember(2)]
public List<MySpecialCollection<T>> Items { get { return items; } }
}
[ProtoContract]
class MySpecialCollection<T>
{
[ProtoMember(1)]
public string Name { get; set; }
private readonly List<Special<T>> items = new List<Special<T>>();
[ProtoMember(2)]
public List<Special<T>> Items { get { return items; } }
}
[ProtoContract]
class Special<T>
{
[ProtoMember(1)]
public string Name { get; set; }
[ProtoMember(2)]
public string Description { get; set; }
[ProtoMember(3)]
private readonly T _source;
T Source { get { return _source; } }
private Special()
{
}
public Special(T source)
{
_source = source;
}
}
[ProtoContract]
[ProtoInclude(2, typeof(Ant))]
[ProtoInclude(3, typeof(Cat))]
[ProtoInclude(4, typeof(Dog))]
interface IBeast
{
[ProtoMember(1)]
string Name { get; set; }
}
[ProtoContract]
class Ant : IBeast
{
public string Name { get; set; }
}
[ProtoContract]
class Cat : IBeast
{
public string Name { get; set; }
}
[ProtoContract]
class Dog : IBeast
{
public string Name { get; set; }
}
public static class Form1
{
private static void Main()
{
MySpecialCollectionList<IBeast> collectionList = GetSpecialCollectionList();
var copy = Serializer.DeepClone(collectionList);
}
private static MySpecialCollectionList<IBeast> GetSpecialCollectionList()
{
var ant = new Ant() { Name = "Mr Ant" };
var cat = new Cat() { Name = "Mr Cat" };
var dog = new Dog() { Name = "Mr Dog" };
var Special = new Special<IBeast>(ant);
var specialCollection1 = new MySpecialCollection<IBeast>() {Items =
{new Special<IBeast>(ant),
new Special<IBeast>(cat),
new Special<IBeast>(dog)}
};
specialCollection1.Name = "Special Collection1";
var specialCollection2 = new MySpecialCollection<IBeast>()
{
Items =
{new Special<IBeast>(ant),
new Special<IBeast>(dog)}
};
specialCollection2.Name = "Special Collection2";
var specialCollectionList = new MySpecialCollectionList<IBeast>()
{
Items ={
specialCollection1, specialCollection2 }
};
specialCollectionList.Name = "Special Collection List";
return specialCollectionList;
}
}