Cast generic collection item type - c#

The following code illustrates a situation I'm having. The real code use different names and get values in other ways, but they match with what I need an answer. Specifically in lines 76-89 (the only lines I control) I need to extract a variable of type "ICollection" with the values and I don't like none of the used approaches. Is there another approach to do it without to create class "AbstractCollection"?
namespace ConsoleApp1
{
using System.Collections.Generic;
using System.Linq;
interface IEntity
{
string Id { get; }
string Name { get; }
}
class Entity : IEntity
{
public Entity(string id, string name)
{
Id = id;
Name = name;
}
public string Id { get; }
public string Name { get; }
}
interface ICollection<TGeneric>
{
IEnumerable<TGeneric> Items { get; }
}
class Collection<TGeneric> : ICollection<TGeneric> where TGeneric : Entity, IEntity
{
public IEnumerable<TGeneric> Items { get; set; }
}
class AbstractCollection<TConcrete, TAbstract> : ICollection<TAbstract> where TAbstract : class, IEntity
{
public AbstractCollection(ICollection<TConcrete> collection)
{
this._Items = new List<TAbstract>();
if (collection?.Items != null)
{
foreach (TConcrete concreteItem in collection.Items)
{
TAbstract abstractItem = concreteItem as TAbstract;
this._Items.Add(abstractItem);
}
}
}
public IEnumerable<TAbstract> Items
{
get { return this._Items; }
set { this._Items = value?.ToList(); }
}
private IList<TAbstract> _Items { get; set; }
}
class EntityCollection : Collection<Entity>
{
public EntityCollection()
{
var items = new List<Entity>()
{
new Entity("1", "Name1"),
new Entity("2", "Name2"),
new Entity("3", "Name3")
};
Items = items;
}
}
class Context
{
public Context()
{
var concreteItems = new EntityCollection();
// I can modify from this line to the end of the method but not any code before.
// I expected values in "list1" but is null.
var list1 = concreteItems as ICollection<IEntity>;
var list2 = concreteItems as ICollection<Entity>;
var abstractItems = new List<IEntity>();
foreach (Entity concreteItem in concreteItems.Items)
{
IEntity abstractItem = concreteItem as IEntity;
abstractItems.Add(abstractItem);
}
// Why "list3" is null?
var list3 = abstractItems as ICollection<IEntity>;
// I want to avoid class "AbstractCollection"
var list4 = new AbstractCollection<Entity, IEntity>(list2);
// Finally "list5" has value in the way I want it.
var list5 = list4 as ICollection<IEntity>;
}
}
class Program
{
static void Main(string[] args)
{
var context = new Context();
}
}
}

Covariance guides to the solution:
interface ICollection<out TGeneric>
{
IEnumerable<TGeneric> Items { get; }
}

Related

How to store Multiple derived class in same list?

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:

Add subtype objects to list of supertype, then return list of subtypes from list of supertypes

I have 3 interfaces.
public interface IItem
{
string Name { get; set; }
}
public interface IEquipable : IItem
{
void Equip();
}
public interface IConsumable : IItem
{
void Use();
}
IEquipable is implemented by the classes Helmet and Bow, and IConsumable is implemented by classes Potion and Food.
Then, I have a class with a property which contains a List of IItem, and proceed to add a few items of both IEquipable and IConsumable after instantiating it.
public class Character
{
public List<IItem> Items { get; private set; }
public Character()
{
this.Items = new List<IItem>();
}
public void AddItem(IItem item)
{
this.Items.Add(item);
}
}
Program.cs
...
Character char = new Character();
char.AddItem(new Potion());
char.AddItem(new Food());
char.AddItem(new Helmet());
char.AddItem(new Bow());
...
Is there a way I can get a List of all IEquipable members from the List of IItems, each AS IEquipable?
I want to do something like
...
List<IEquipable> equipmentList = //do something to char.Items and get all items of type IEquipable.
IEquipment equipment = equipmentList.First(...)
equipment.Equip();
...
I've tried using List<IEquipable> equipmentList = char.Items.OfType<IEquipable>().ToList() but the resulting list ends up empty.
I implemented (and fixed minor typos in) your code like this:
void Main()
{
Character character = new Character();
character.AddItem(new Potion());
character.AddItem(new Food());
character.AddItem(new Helmet());
character.AddItem(new Bow());
List<IEquipable> equipmentList = character.Items.OfType<IEquipable>().ToList();
}
public class Potion : IConsumable
{
public string Name { get; set; }
public void Use()
{
throw new NotImplementedException();
}
}
public class Food : IConsumable
{
public string Name { get; set; }
public void Use()
{
throw new NotImplementedException();
}
}
public class Helmet : IEquipable
{
public string Name { get; set; }
public void Equip()
{
throw new NotImplementedException();
}
}
public class Bow : IEquipable
{
public string Name { get; set; }
public void Equip()
{
throw new NotImplementedException();
}
}
public interface IItem
{
string Name { get; set; }
}
public interface IEquipable : IItem
{
void Equip();
}
public interface IConsumable : IItem
{
void Use();
}
public class Character
{
public List<IItem> Items { get; private set; }
public Character()
{
this.Items = new List<IItem>();
}
public void AddItem(IItem item)
{
this.Items.Add(item);
}
}
Your exact code (albeit char renamed to character) works perfectly fine. The equipmentList ends up with two elements. The issue you're seeing, i.e. "the resulting list ends up empty", is not reproducible with the code you've posted.
You can use the OfType method
Filters the elements of an IEnumerable based on a specified type.
Signature
public static IEnumerable<TResult> OfType<TResult> (this IEnumerable source)
Usage
var equipable = Character.Items.OfType<IEquipable>();
Or encapsulate it as a method in the instance or an extension method if you like
So it does work like I wanted. My actual code just had another issue and I'm a dummy for not actually posting that. So here it is, for future reference.
using System.Collections.Generic;
using RolePlayGame.Library.Items.Backstage;
using System.Linq;
using System.Text;
using System;
namespace RolePlayGame.Library.Characters.Backstage
{
public class Inventory
{
public List<IItem> StoredItems { get; private set; }
public List<EquippedItem> Gear { get; private set; }
public Inventory()
{
this.StoredItems = new List<IItem>();
this.Gear = new List<EquippedItem>();
}
public bool HasItem(string name)
{
return this.StoredItems.Exists(item => item.Name == name);
}
public bool HasItem(IItem item)
{
return this.StoredItems.Contains(item);
}
public void RemoveItem(string name)
{
int firstIndex = this.StoredItems.FindIndex(item => item.Name == name);
if (firstIndex != -1)
{
this.StoredItems.RemoveAt(firstIndex);
}
}
public void RemoveItem(IItem item)
{
int firstIndex = this.StoredItems.IndexOf(item);
if (firstIndex != -1)
{
this.StoredItems.RemoveAt(firstIndex);
}
}
public void AddItem(IItem item, int quantity)
{
for (int i = 0; i < quantity; i++)
{
this.StoredItems.Add(item);
}
}
public void AddItem(IItem item)
{
this.StoredItems.Add(item);
}
public bool CheckEquipmentSlot(EquipmentSlot slot)
{
return this.Gear.Exists(item => item.UsedSlots.Contains(slot));
}
public bool HasEquipment(IEquipment equipment)
{
return this.Gear.Exists(item => item.Item == equipment);
}
public void AddEquipment(IEquipment equipment)
{
IEquipment alreadyEquipped;
foreach (EquipmentSlot slot in equipment.SlotsUsed)
{
if (this.Gear.Exists(item => item.UsedSlots.Contains(slot)))
{
alreadyEquipped = this.Gear.Find(item => item.UsedSlots.Contains(slot)).Item;
this.RemoveEquipment(slot);
this.StoredItems.Add(alreadyEquipped);
}
}
EquippedItem newEquipment = new EquippedItem(equipment);
this.Gear.Add(newEquipment);
}
public void RemoveEquipment(EquipmentSlot slot)
{
this.Gear.RemoveAll(equipment => equipment.UsedSlots.Contains(slot));
}
public int GetAttributeBonusTotal(AttributeType attribute)
{
int bonusTotal = 0;
foreach (IEquipment item in this.StoredItems.OfType<IEquipment>().ToList())
{
bonusTotal += item.GetAttributeBonus(attribute);
}
return bonusTotal;
}
public int GetCarryWeight()
{
int totalWeight = 0;
foreach (IItem item in StoredItems)
{
totalWeight += item.Weight;
}
return totalWeight;
}
public string GearToString()
{
StringBuilder builder = new StringBuilder();
builder.Append(" Equipped Gear:");
foreach (EquippedItem equipment in this.Gear)
{
builder.Append($"\n {equipment.Item.Name}");
}
return builder.ToString();
}
public string ItemsToString()
{
StringBuilder builder = new StringBuilder();
builder.Append(" Inventory:");
foreach (IItem item in this.StoredItems.Distinct())
{
builder.Append($"\n {item.Name} x {this.StoredItems.FindAll(value => value == item).Count()}");
}
return builder.ToString();
}
public int GetDefenseRateAgainstTypeTotal(DamageType againstType)
{
int rate = 0;
List<IOutfit> outfits = this.Gear.Select(value => value.Item).OfType<IOutfit>().ToList();
foreach (IOutfit item in outfits)
{
rate += item.GetDefenseRateAgainstType(againstType);
}
return rate;
}
}
}
One of the last lines has the problem (now fixed). List<IOutfit> outfits = this.Gear.Select(value => value.Item).OfType<IOutfit>().ToList(); used to be List<IOutfit> outfits = this.Gear.OfType<IOutfit>().ToList();. But Gear is of type List<EquippedItem>, and EquippedItem is not an implementation of IItem.
Here is EquippedItem.cs
using RolePlayGame.Library.Items.Backstage;
using System.Collections.Generic;
namespace RolePlayGame.Library
{
public class EquippedItem
{
public List<EquipmentSlot> UsedSlots { get; set; }
public IEquipment Item { get; set; }
public EquippedItem(IEquipment equipment)
{
this.Item = equipment;
this.UsedSlots = equipment.SlotsUsed;
}
}
}
I needed to select the Item property from the items inside Gear as another list before doing the type filtering with .OfType<IOutfit>(). That's where .Select(value => value.Item) enters the stage.
So that's that. I'll learn to post actual code for future questions.

Dbset as hashset in the Entity Framework

I need to merge data from tables in the database with data based on some logic from third-party sources. I implemented this logic via hashset, for which I overloaded the GetHashCode and Equals methods for entities. Now I don't understand how I can save the result of work in the database via DbSet, with subsequent data loading and subsequent merging (the task of merging/supplementing is periodic)
The directories are quite voluminous, so working through hashset speeds up the process.
class Program
{
private class DummyDbContext { public void SaveChangesAsync() { }}
static void Main(string[] args)
{
var dbContext = new DummyDbContext(); // TODO: Get from DI
// TODO: I don't know how to do it yet with HashSets
var currentFactories = LoadCurrentFactoriesFromDb(dbContext);
var currentProducts = LoadCurrentProductsFromDb(dbContext);
var thirdPartyData = GetThirdPartyData();
foreach (var data in thirdPartyData)
{
/*
In reality, the logic is more complicated, because some data transformation is required.
Some data may be missing. That is why comparing two objects is not quite easy (see the method Product.Equals)
*/
var factory = new Factory(data.otherFactory.Name);
var product = new Product(data.otherProduct.Property1, data.otherProduct.Property2, factory);
if (currentFactories.TryGetValue(factory, out var existedFactory))
factory = existedFactory;
else
currentFactories.Add(factory);
if (currentProducts.TryGetValue(product, out var existedProduct))
{
if (!existedProduct.Factory.Equals(factory))
throw new InvalidOperationException(); // TODO:
product = existedProduct;
factory.Products.Add(product); // TODO:
}
else
currentProducts.Add(product);
}
// **how to implement the saving of combined directories, in hashsets, in the database ?**
dbContext.SaveChangesAsync();
}
private static IEnumerable<(ThirdPartyFactory otherFactory, ThirdPartyProduct otherProduct)> GetThirdPartyData()
{
return new (ThirdPartyFactory otherFactory, ThirdPartyProduct otherProduct)[]
{
( new ThirdPartyFactory () {Name = "SomeFactory"}, new ThirdPartyProduct() {Property1 = "ProductName1"}),
( new ThirdPartyFactory () {Name = "SomeFactory"}, new ThirdPartyProduct() {Property1 = "ProductName2"}),
( new ThirdPartyFactory () {Name = "SomeFactory"}, new ThirdPartyProduct() {Property2 = "Property1"})
};
}
private static HashSet<Factory> LoadCurrentFactoriesFromDb(DummyDbContext context)
{
// DbContext.DbSet<Factory>.GetAll()
return new HashSet<Factory>();
}
private static HashSet<Product> LoadCurrentProductsFromDb(DummyDbContext context)
{
// DbContext.DbSet<Product>.GetAll()
return new HashSet<Product>();
}
}
public class Product
{
public Product(string property1, string property2, Factory factory)
{
Property1 = property1;
Property2 = property2;
Factory = factory;
}
public long Id { get; set; }
public string Property1 { get; }
public string Property2 { get; }
public Factory Factory { get; }
public override bool Equals(object? obj)
{
if (obj == null)
return false;
var product = (Product) obj;
return (string.IsNullOrWhiteSpace(Property1) && string.IsNullOrWhiteSpace(product.Property1)
|| string.CompareOrdinal(this.Property1, product.Property1) == 0)
&& (string.IsNullOrWhiteSpace(Property2) && string.IsNullOrWhiteSpace(product.Property2)
|| string.CompareOrdinal(this.Property2, product.Property2) == 0);
}
public override int GetHashCode()
{
return HashCode.Combine(Property1, Property2).GetHashCode();
}
}
public class Factory
{
public Factory(string name)
{
Name = name;
}
public long Id { get; set; }
public string Name { get; }
public HashSet<Product> Products { get; set; }
}
public class ThirdPartyProduct
{
public string Property1 { get; set; }
public string Property2 { get; set; }
}
public class ThirdPartyFactory
{
public string Name { get; set; }
}
Is it possible to implement this ? Or do I need to convert data from DbSet to HashSet and then back ? But won't I lose information about entities inside the context during such transformations ?

How to mutate a list of custom objects in GraphQL for .NET

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

Protobuf Inheritance and Generics

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

Categories