Determine type equivalence

Is this possible in C # (I use .Net 4.5, but ask in a more general case) to determine if two implementations of a generic type are functionally equivalent?

As an example of a need, suppose I have an IMapper interface defined as:

 public interface IMapper<TTo, TFrom> { TTo MapFrom(TFrom obj); TFrom MapFrom(TTo obj); } 

My ideal implementation:

 public class MyMapper : IMapper <A, B> { A MapFrom(B obj) {...} B MapFrom(A obj) {...} } 

This will be functionally equivalent to:

 public class MyEquivalentMapper : IMapper <B, A> { B MapFrom(A obj) {...} A MapFrom(B obj) {...} } 

but the compiler (rightfully) recognizes them as different types. Is there a way in which the compiler can treat these two types as equivalent (and perhaps even interchangeably)?

I also looked at this:

 public interface ISingleMapper<out TTo, in TFrom> { TTo MapFrom(TFrom obj); } public class MyAlternateMapper : ISingleMapper<A, B>, ISingleMapper<B, A> { A MapFrom(B obj) {...} B MapFrom(A obj) {...} } 

but I found that I can not correctly identify the abstraction, so that I can introduce (in the constructors, etc.) a specific class without creating an "average person" interface:

 public interface IBidirectionalMapper<TTo, TFrom> : ISingleMapper<TTo, TFrom>, ISingleMapper<TFrom, TTo> { TTo MapFrom(TFrom obj); TFrom MapFrom(TTo obj); } public class MyAlternateMapper : IBidirectionalMapper<A, B> { A MapFrom(B obj) {...} B MapFrom(A obj) {...} } 

I think the “average person” approach is more “correct”, but I would prefer not to create an extra type. Furthermore, it still carries a problem when replacing type arguments creates two different, but functionally equivalent types.

Is there a better way to achieve my goal?

+7
source share
4 answers

You can have one correlator that performs both translations, but just needs to be oriented, because in your case there is always a conjugation of “my object” and “database object”.

 interface IDbTypeModel<T, TDb> { T FromDb(TDb dbObj); TDb ToDb(T obj); } 
+1
source

Given this definition:

 public interface IMapper<out TTo, in TFrom> { TTo MapFrom(TFrom obj); TFrom MapFrom(TTo obj); } 

The types IMapper<A, B> and IMapper<B, A> actually not equivalent due to asymmetric covariant / contravariant common parameters. But ignoring it ...

You can try something like the following (although this can have problems when A and B are of the same type).

 //Represents an oriented one-way mapper public interface IDirectionalMapper<A, B> { B Map(A obj); } //Represents an oriented two-way mapper public interface IBidirectionalMapper<A, B> : IDirectionalMapper<A, B>, IDirectionalMapper<B, A> { } //Represents an unoriented two-way mapper public interface IUndirectedMapper<A, B> : IBidirectionalMapper<A, B>, IBidirectionalMapper<B, A> { } 

Now, for example, you can define IUndirectedMapper<int, string> some place in your code, and then use it as both IBidirectionalMapper<int, string> and IBidirectionalMapper<string, int> .

Edit

These definitions give you three errors of the following taste.

IBidirectionalMapper<A,B> cannot implement both IDirectionalMapper<A,B> and IDirectionalMapper<B,A> , since they can be combined for some parameter substitutions of type

This approach does not seem to work, sorry.

+1
source

It is impossible to express the concept that a IGenericInterface<T,U> should be considered equivalent to IGenericInterface<U,T> , since the methods of these interfaces will be connected in different ways. For example, if a class that implements such an interface

 MyClass<T,U> : IGenericInterface<T,U> { public T Convert(U param) { Console.WriteLine("U to T"); } public U Convert(T param) { Console.WriteLine("T to U"); } } 

The choice of this function depends on the roles of T and U. If you are doing something like:

 MyClass2<T,U> { ... inside some method T myT; U myU; IGenericInterface<T,U> myThing = new MyClass<T,U>(); myT = myThing.Convert(myU); } 

The Convert method above will be bound to a method that outputs “UT”, even inside something like MyClass2<Foo,Foo> , where both types are the same.

0
source

It is not clear what you mean by "equivalence." If you mean two types, they are equivalent because they have the same elements and the members have the same signature, then you can use reflection to determine that:

  public class TypeComparer : IEqualityComparer<MemberInfo> { public bool Equals(MemberInfo x, MemberInfo y) { return x.ToString() == y.ToString(); } public int GetHashCode(MemberInfo obj) { return obj.GetHashCode(); } } public static bool AreTypesEqual(Type type1, Type type2) { return type1.GetMembers(). SequenceEqual(type2.GetMembers(), new TypeComparer()); } 

If the order of the members does not matter:

  public static bool AreTypesEqual2(Type type1, Type type2) { return type1.GetMembers().OrderBy(e=>e.ToString()). SequenceEqual(type2.GetMembers().OrderBy(e=>e.ToString()), new TypeComparer()); } 
0
source

All Articles