簡體   English   中英

確定類型等價

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM