The core of the issue here is that you're unable to create code that works for both ThirdPartyTypeA
and ThirdPartyTypeB
, because there is no formal link between them, and because of that the compiler refuses to understand/acknowledge that the posted code works for both types.
There are several ways around this:
1. Implement inheritance
Less appropriate for third party types, but if all types were owned by you, you should first ask yourself if there is a common inheritance between the two, before moving to step 2.
I want to stress here that inheritance is not always better than interfaces. Inheritance can be abused, and excessive inheritance is a pain to deal with.
I'm suggesting looking at inheritance before interfaces because problems solved by inheritance often exist on a larger scope than problems solved by interfaces. Look at the macro (inheritance) before you look at the micro (interfaces).
2. Implement interfaces
When there is no inheritance logic; the second option is to implement a basic interface between them.
A simple example:
public interface IFoo
{
string Name;
}
public class ThirdPartyTypeA : IFoo
{
public String Name { get; set; }
}
public class ThirdPartyTypeB : IFoo
{
public String Name { get; set; }
}
And then:
public T CreateFromMyType<T>(MyType myType) where T : IFoo, new()
{
var obj = new T();
obj.Name = myType.Name;
return obj;
}
And its usage:
ThirdPartyTypeA obj = CreateFromMyType<ThirdPartyTypeA>(myType);
This is just a rudimentary example to show you how to implement it on a basic level. There are multiple unknowns in your example code (e.g. how diverse the enum conditions are, what actually changes between different enum values, ...) that need to be addressed before you can create a fitting solution.
3. Reflection, if you must.
I don't like excessive use of reflection. However, it does give you the ability to get/set properties based on a string name, thus bypassing the type safety that C# provides.
Unless you can find a justifiable reason to not use interfaces, I consider reflection an inferior solution to interface implementation. Not because it doesn't work, but because it throws type safety out the door, trades compile time errors for runtime errors, and it's easy to shoot yourself in the foot with (the nameof()
operator helps to not shoot yourself in the foot, but it's a partial improvement).
4. Convert to/from a string-serialized type
Similar to reflection, you could convert your data to a JSON string (with the common property name) and then convert that JSON to a third party type. String-based serializers access properties based on their name and ignores C#'s type safety.
This is really just using reflection by a different name. It slightly avoids type unsafety (because you can define your intermediary DTO class in code), but it still throws type safety out the door and trades compile time errors for runtime errors.
5. Move to a type-unsafe language.
I'm aware that this is not a realistic solution, but I do want to point this out.
Type safety exists for a reason. Before type safety existed, applications heavily depended on the developer's aptitude at managing a complex web of property references.
A similar thing happened for C/C++ pointers. While very powerful, they were also very complicated, easy to shoot yourself in the foot with, and nigh impossible to easily debug. This is why C# has moved on to use reference types, effectively having the compiler do the memory allocation for you.
Properly written C++ outperforms C#, but the difficulty in writing that perfect C++ is so much higher than working with reference types in C#.
With type safety, we're at the same crossroads. Do we rely on developers managing it all themselves, or do we automate it in order to make things so much easier (at the cost of minor inconveniences)?
Interesting discussions on this topic can be found by following "Typescript vs Javascript" discussions. Typescript was created specifically to introduce type safety to the otherwise type-unsafe Javascript. I would argue that the current rising popularity of Typescript proves that type safety is something the development sector wants to have.
Unless you create a formal link between the two third party classes (inheritance or interface), you're effectively trying to ignore the globally enforced rule of type safety. This suggests that you approach is simply not compatible with C#'s approach.
I suggest adapting your approach instead of trying to go around the ideology of the language you're programming in.
ThirdPartyTypeA[]
s andThirdPartyTypeB
s fromMyType
s or is itreturn null;
?