2

I have a need to translate data from provider A to provider B. The data is typically pretty consistent, but, often has minor differences; for example:

public sealed class ProviderOneFoo {
    public int Bar { get; set; }
}
public sealed class ProviderTwoFoo {
    public long Barr { get; set; }
}

My present idea is to utilize interfaces to work with the data instead of dedicated types:

public interface IFoo {
    object Bar { get; set; }
}
public sealed class ProviderOneFoo : IFoo {
    public object Bar { get; set; }
}
public sealed class ProviderTwoFoo : IFoo {
    private long _bar { get; set; }
    public long Barr { get => _bar; set => _bar = value; }
    public object Bar { get => _bar; set => _bar = long.Parse(value.ToString()); }
}

However, I don't like this setup for a few reasons:

  • The types might not match the provider's type specifications.
  • The property can be duplicated which confuses consumers working directly with ProviderTwoFoo.
  • Increased maintenance requirements due to the addition of fields that wouldn't typically be required, and additional properties.
  • Danger in the assignments to both provider's models due to the use of object when types don't match.
    • I'm aware there are better ways, I just wrote this quickly to summarize my current thoughts.

Currently, I have an idea to utilize reflection and allow properties that can be translated, to be assigned an attribute like Translatable that specifies the internal name of the property. However, I don't like this route for two very specific reasons:

  • Since enum isn't compile time constant, magic strings have to be used to define the internal name leading to inconsistencies.
  • Reflection will introduce some potentially pretty high overhead.

The major advantages to the reflection approach is that each data model can use the types specified by the provider and there's reduced maintenance requirements since a centralized source performs the translation through the attributes.


Are there any other alternative ways to translate data models that could allow lightweight translation between types with inconsistencies?

1
  • 1
    I'm hoping someone will answer with a library that does this kind of thing, but surely you don't want to go with some kind of generic interface to object - losing all the type-safety (and performance) that you get with proper .NET types. A solution using reflection - especially if it generates code and doubly-especially if you didn't have to write it yourself (it's probably got 100s of edge cases) - would be ideal, which is why I'm hoping somebody will identify a library.
    – davidbak
    Commented Aug 20, 2021 at 22:05

2 Answers 2

6

need to translate data from provider A to provider B

public static ProviderTwoFoo ConvertToBProvider(this ProviderOneFoo data)
{
    return new ProviderTwoFoo 
    {
        Barr = data.Bar
    };
}  

// Usage
var providerBdata = providerAdata.ConvertToBProvider();
  • Type it only once
  • Supports all possible conversion logics (main benefit)
  • Readable and comprehensible for anybody working with the code

Notice that programmers writing the code only 10% of their time - so trying to save time on typing with third party dependency or complex reflection logic will increase reading time or time required to understand how conversion works for other programmers.

1

I saw your now closed question on Code Review.

Look at the Adapter design pattern. Think about that general idea. Existing classes are encapsulated by another class that exposes a desired uniform/standard interface. Thus Adapter.Bar would call ProviderFoo.Barrrrrr (whatever). Have an adapter for each "translation API" need.

I see there will be many Adapters for the many-to-many translations. But I can see a factory pattern for instantiating Adapter-adaptee composed objects.

Open/Close principle goodness: ProviderFoo methods do not need name, signature changes, funky interface implementations, etc.

I take it method and property, Bar for example, spelling and method signatures are essentially arbitrary. Similar, yes, but no defined grammar, pattern, whatever. So I see a unique Adapter for each translation task. Nonetheless the Adapter's exposed API is consistent.

If there are natural groupings or sub-groupings of "output" APIs, group consistency can be enforced with a base abstract class. And an instantiated (concrete) Adapter could be inherited for sub-grouping adapters.



Go to MSDN and read about .NET's very rich library of database adapters. They are amazingly flexible. Maybe it will give you some ideas and insights.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.