[英]Determine type equivalence
是否有可能在C#(我使用.Net 4.5,但更普遍地要求)確定泛型類型的兩個實現是否在功能上等效?
作為需求的一個例子,假設我有一個IMapper
接口定義為:
public interface IMapper<TTo, TFrom>
{
TTo MapFrom(TFrom obj);
TFrom MapFrom(TTo obj);
}
我理想的實現是:
public class MyMapper : IMapper <A, B>
{
A MapFrom(B obj) {...}
B MapFrom(A obj) {...}
}
這在功能上等同於:
public class MyEquivalentMapper : IMapper <B, A>
{
B MapFrom(A obj) {...}
A MapFrom(B obj) {...}
}
但編譯器(正確地)將這些識別為不同的類型。 有沒有辦法告訴編譯器將這兩種類型視為等效(甚至可以互換)?
我也看過這個:
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) {...}
}
但我發現我無法正確識別抽象,因此我可以注入(進入構造函數等)具體類而無需創建“中間人”接口:
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) {...}
}
我認為“中間人”方法更“正確”,但我不想創造一個多余的類型。 此外,它仍然存在交換類型參數創建兩個不同但功能相同的類型的問題。
有沒有更好的方法來實現我的目標?
鑒於此定義:
public interface IMapper<out TTo, in TFrom>
{
TTo MapFrom(TFrom obj);
TFrom MapFrom(TTo obj);
}
由於非對稱協變/逆變通用參數IMapper<A, B>
和IMapper<B, A>
類型實際上不等效。 但是,忽略那......
您可以嘗試類似以下內容(盡管當A和B具有相同類型時可能會出現問題)。
//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>
{
}
現在,例如,您可以在代碼中的某個位置定義IUndirectedMapper<int, string>
,然后將其用作IBidirectionalMapper<int, string>
和IBidirectionalMapper<string, int>
。
這些定義給出了以下風味的三個錯誤。
IBidirectionalMapper<A,B>
不能同時實現IDirectionalMapper<A,B>
和IDirectionalMapper<B,A>
因為它們可能統一為某些類型參數替換
看起來這種方法不起作用,抱歉。
您可以使用單個映射器來執行兩種轉換,但只需將其定向,因為在您的情況下始終存在“我的對象”和“數據庫對象”配對。
interface IDbTypeModel<T, TDb>
{
T FromDb(TDb dbObj);
TDb ToDb(T obj);
}
沒有辦法表達IGenericInterface<T,U>
應被視為等同於IGenericInterface<U,T>
,因為這些接口的方法將以不同方式綁定。 例如,如果一個類實現了這樣的接口
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"); }
}
調用哪個函數的選擇取決於T和U的作用。如果有人這樣做:
MyClass2<T,U>
{
... inside some method
T myT;
U myU;
IGenericInterface<T,U> myThing = new MyClass<T,U>();
myT = myThing.Convert(myU);
}
上面的Convert
方法將綁定到輸出“U to T”的方法,即使在兩個類型相同的MyClass2<Foo,Foo>
類的內容中也是如此。
目前還不清楚“等價”是什么意思。 如果你的意思是兩種類型是等價的,因為它們具有相同的成員,並且成員具有相同的簽名,那么你可以使用反射來確定:
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());
}
如果成員的順序無關緊要:
public static bool AreTypesEqual2(Type type1, Type type2)
{
return type1.GetMembers().OrderBy(e=>e.ToString()).
SequenceEqual(type2.GetMembers().OrderBy(e=>e.ToString()), new TypeComparer());
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.