vendredi 9 juin 2017

Most Effective Way to Decompose / Recompose An Object Hierarchy in .NET 4.5+ / .NET Standard 1.0+ / .NET Core 1.0+

Scenario

I have a use case where I need do decompose an hierarchical object tree into a set of its constituent objects. Later on, I will also need to recompose those objects back into their original form.

Goals

My goals are as follows.

  • Determine the fastest and most processor and/or memory efficient ways to decompose/recompose the objects. (This code will process millions of objects so saving even a few ticks is useful.)
  • Locate any existing libraries or examples which may facilitate this decomposition/recomposition scenario or which may demonstrate how others have done something similar.
  • Compile a list of strategies, methods, and techniques for decomposing an object hierarchy (in .NET 4.5+, .NET Core) into its elementary objects and recomposing those elementary objects back into an hierarchy. (Note: There is no such thing as too many ideas, too many techniques, or too many examples here.)

'Givens' / Requirements

  • This functionality will be implemented in .NET Core 1.x and above. Backwards compatibility with .NET 4.5+ would be a plus.
  • The structure of the object tree is not necessarily known in advance.
    • The decomposition component must be able to work with any provided object tree.
  • The object hierarchy may be many layers deep.
    • The decomposition will run recursively until it reaches the lowest level of the object tree. Most objects (except as described below) will be decomposed.
    • Arrays and collections may optionally be kept intact rather than being decomposed. This will vary from usage to usage. I would say that generally, Arrays, Dictionaries, simple lists (e.g. lists of strings) will generally not be decomposed. Complex lists (e.g. lists of objects will likely decompose.)
  • Recomposition of object hierarchies may be full or partial.
  • During recomposition, other objects may be inserted into the object hierarchy (or existing objects may be replaced) to make completely new types of objects.

Potentially Important Issues Not Yet Considered

I am still at an early stage in analyzing how to accomplish this object. (Frankly, I feel like I am flying blind here.) There are probably many important factors I have not considered. These include:

  • Any potential impact of self-referencing classes.
  • Implications or impact of other potential element or object types.

Resources I am Currently Reviewing

I have a reasonable idea of generally how to accomplish the decomposition and recomposition through reflection. However, I am not confident that I know how to do it well, do it efficiently, or do it in a way that properly handles every issue.

Here is a list of some of the resources I am reviewing now.

Demo Class / Object Hierarchy

I have created a very simple for-demonstration-purposes-only class hierarchy which represents the types of elements I would expect to find in the object hierarchies which we will process.

These include:

  • ValueType - (e.g. integer) Property
  • String - Property
  • DateTime - Property
  • Custom Class - Property
  • Dictionary - Collection
  • Lists - Collection
  • Array - Field

There is a single base class which generates an Id of type Guid on the parent and all children.

public class EntityBase
{
    public EntityBase()
    {
        Id = Guid.NewGuid();
    }

    public Guid Id { get; set; }
}

The root object in the demo hierarchy is of type Person. It contains various general properties of type string, int, and DateTime just as one would find in most any class. It also contains List and Dictionary collection classes, as an array, and a reference to single custom object.

public class Person : EntityBase
{
    public Person()
    {
        Phones = new List<Phone>();
        Addresses = new List<Address>();
        Passwords = new Dictionary<string, string>();
        FavoriteFood = new FoodPreference();
    }

    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int Weight { get; set; }
    public DateTime DateOfBirth { get; set; }
    public FoodPreference FavoriteFood {get; set;}
    public string[] Dogs = { "Shayna", "Sport" };
    public Dictionary<string, string> Passwords { get; set; }
    public ICollection<Phone> Phones { get; set; }
    public ICollection<Address> Addresses { get; set; }
}

There is a collection of phone numbers.

public class Phone : EntityBase
{
    public string PhoneNumber { get; set; }
}

There is a collection of postal addresses.

public class Address : EntityBase
{
    public string StreetAddress { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string PostalCode { get; set; }
}

There is a custom class with some detail on a favorite food.

public class FoodPreference : EntityBase
{
    public string FoodCategory { get; set; }
    public string FoodName { get; set; }
}

Just to put it all together, here is a sample method which populates the heirarchy with dummy data.

    public static Person BuildPerson()
    {
        return new Person
        {
            FirstName = "Anthony",
            LastName = "Gatlin",
            Weight = 154, // I wish. :)
            DateOfBirth = DateTime.Parse("01/01/1970"),
            Phones = new List<Phone>
            {
                new Phone {PhoneNumber = "601-555-1212"},
                new Phone {PhoneNumber = "601-555-1213"}
            },
            Addresses = new List<Address>
            {
                new Address {StreetAddress = "111 Country Rd", City = "Heidelberg", State = "MS", PostalCode = "39349"}
            },
            Passwords = new Dictionary<string, string>
            {
                {"google","googlepass" },
                {"skype","skypepass" },
                {"facebook","facebookpass" }
            }
        };
    }

The sample object hierarchy can be retrieved from http://ift.tt/2rfSKl3.

Output From Sample Data

Following is a simple JSON dump of sample data generated for this hierarchy.

{ "Dogs": [ "Shayna", "Sport" ], "FirstName": "Anthony", "LastName": "Gatlin", "Weight": 154, "DateOfBirth": "1970-01-01T00:00:00", "FavoriteFood": { "FoodCategory": "Baked Goods", "FoodName": "Chocolate Cake", "Id": "0c516c4d-ff64-4b8d-bb44-b430aa8d3ce5" }, "Passwords": { "google": "googlepass", "skype": "skypepass", "facebook": "facebookpass" }, "Phones": [ { "PhoneNumber": "601-555-1212", "Id": "57bdfdcb-4232-40e4-aab8-4c6387029257" }, { "PhoneNumber": "601-555-1213", "Id": "b591afc3-6e91-4030-ad26-00beefceca43" } ], "Addresses": [ { "StreetAddress": "111 Country Rd", "City": "Heidelberg", "State": "MS", "PostalCode": "39349", "Id": "94cc5e37-db96-44b7-869a-818968d99ddd" } ], "Id": "629ae27e-17aa-49ad-823a-2cd2ebf0cb66" }

Expected Result

Once the objects have been decomposed from the object hierarchy, I will end up storing some sort of simple hierarchy which will allow me to recompose the objects.

Given the following Id Guids ...

  • 629ae27e-17aa-49ad-823a-2cd2ebf0cb66 // Person Id
  • 0c516c4d-ff64-4b8d-bb44-b430aa8d3ce5 // FavoriteFood
  • 57bdfdcb-4232-40e4-aab8-4c6387029257 // Phone1 Id
  • b591afc3-6e91-4030-ad26-00beefceca43 // Phone2 Id
  • 94cc5e37-db96-44b7-869a-818968d99ddd // Address Id

we may end up with a very simple JSON Hierarchy like so.

{
"Person":{
"Id":"629ae27e-17aa-49ad-823a-2cd2ebf0cb66", "FavoriteFood":{
"Id":"0c516c4d-ff64-4b8d-bb44-b430aa8d3ce5" }, "Phone":[
{
"Id":"57bdfdcb-4232-40e4-aab8-4c6387029257" }, {
"Id":"b591afc3-6e91-4030-ad26-00beefceca43" } ], "Address":[
{
"Id":"94cc5e37-db96-44b7-869a-818968d99ddd" } ] } }

Each object with dependencies will have its own one-level dependency tree.

The above format is just an example, and I am completely open to (read desperately seeking) ideas on better ways to do this.

Each of the elementary objects will actually be serialized to JSON or MsgPack. We will be able to fully or partially reassemble the objects from the hierarchy when required.

Thank You!

I am really looking for any guidance, recommendations, advice, ideas, tips, examples, code snippets, libraries, or anything else you can offer that will help me to accomplish this task efficiently.

Thank you so very much, in advance, for your help! It is extremely appreciated.





Aucun commentaire:

Enregistrer un commentaire