C# 确定类型等价性
在C#(我使用的是.NET4.5,但要求更一般)中是否可以确定泛型类型的两个实现在功能上是否等效 作为需求示例,假设我有一个C# 确定类型等价性,c#,types,interface,C#,Types,Interface,在C#(我使用的是.NET4.5,但要求更一般)中是否可以确定泛型类型的两个实现在功能上是否等效 作为需求示例,假设我有一个IMapper接口,定义为: public interface IMapper<TTo, TFrom> { TTo MapFrom(TFrom obj); TFrom MapFrom(TTo obj); } 公共接口IMapper { TTo映射自(TFrom obj); t从映射开始(TTo obj); } 我的理想实现方式是: publi
IMapper
接口,定义为:
public interface IMapper<TTo, TFrom>
{
TTo MapFrom(TFrom obj);
TFrom MapFrom(TTo obj);
}
公共接口IMapper
{
TTo映射自(TFrom obj);
t从映射开始(TTo obj);
}
我的理想实现方式是:
public class MyMapper : IMapper <A, B>
{
A MapFrom(B obj) {...}
B MapFrom(A obj) {...}
}
公共类MyMapper:IMapper
{
来自(B obj){…}的映射
B映射自(A obj){…}
}
这在功能上等同于:
公共类MyEquivalentMapper:IMapper
{
B映射自(A obj){…}
来自(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) {...}
}
公共接口ISingleMapper
{
TTo映射自(TFrom obj);
}
公共类MyAlternateMapper:
ISingleMapper,
ISingleMapper
{
来自(B obj){…}的映射
B映射自(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) {...}
}
公共接口IBI方向映射器:
ISingleMapper,
ISingleMapper
{
TTo映射自(TFrom obj);
t从映射开始(TTo obj);
}
公共类MyAlternateMapper:IBI方向映射器
{
来自(B obj){…}的映射
B映射自(A obj){…}
}
我认为“中间人”方法更“正确”,但我不希望创建多余的类型。此外,它仍然存在一个问题,即交换类型参数会创建两个不同但功能相同的类型
有没有更好的方法来实现我的目标?根据以下定义:
public interface IMapper<out TTo, in TFrom>
{
TTo MapFrom(TFrom obj);
TFrom MapFrom(TTo obj);
}
公共接口IMapper
{
TTo映射自(TFrom obj);
t从映射开始(TTo obj);
}
由于非对称协变/逆变泛型参数,类型IMapper
和IMapper
实际上是不等价的。但是,忽略这一点
您可以尝试以下方法(尽管当A和B的类型相同时可能会出现问题)
//表示定向单向映射器
公共接口IDirectionalMapper
{
B地图(A obj);
}
//表示定向双向映射器
公共接口方向映射器
:IDirectionalMapper,IDirectionalMapper
{
}
//表示无方向的双向映射器
公共接口IUndirectedMapper
:IBI方向映射器,IBI方向映射器
{
}
现在,例如,您可以在代码中的某个位置定义一个iIndirectedMapper
,然后将其用作iDirectionalMapper
和iDirectionalMapper
编辑
这些定义给出了以下类型的三个错误
IDirectionalMapper
无法同时实现IDirectionalMapper
和IDirectionalMapper
,因为它们可以统一用于某些类型参数替换
抱歉,这种方法似乎不起作用。您可以使用一个映射器同时进行两种翻译,但只需将其定向即可,因为在您的情况下,始终存在“我的对象”和“数据库对象”配对
接口IDbTypeModel
{
T FromDb(TDb dbObj);
TDb-ToDb(T-obj);
}
无法表达这样一个概念,即IGenericInterface
应被视为等同于IGenericInterface
,因为这些接口的方法将以不同的方式绑定。例如,如果一个类实现了这样一个接口
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"); }
}
MyClass:IGenericInterface
{
公共T转换(U参数){Console.WriteLine(“U到T”);}
公共U转换(T参数){Console.WriteLine(“T到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);
}
MyClass2
{
…在某种方法中
T-myT;
吴敏;
IGenericInterface myThing=新MyClass();
myT=myThing.Convert(myU);
}
上面的
Convert
方法将绑定到输出“U到T”的方法,即使在MyClass2
中,这两种类型都是相同的。您真的不清楚“等价”是什么意思。如果您的意思是两种类型是等效的,因为它们具有相同的成员,并且成员具有相同的签名,那么您可以使用反射来确定:
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());
}
(现在不是在linqpad面前)您对IUndirectedMapper的定义不会导致可怕的“类型统一”编译时错误吗?哦。。。没错。而且没有
中的A!=B
支持。@TimothyShields,感谢您指出co/CONTRAVANCE问题。我已经改正了。看起来我只需要采用一种编码实践,总是按照字母顺序或类似的方式声明我的映射器类型。如果你揭示了你在这个问题中概述的目标的动机,那么我们可能会看到另一种方法。@TimothyShields,目标就是我发布的示例。我正在尝试将数据库表项映射到.Net对象实体并返回。最好有一个同时执行两种翻译的映射器,而不是有两个映射器。我只是想看看有没有更好的办法。
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"); }
}
MyClass2<T,U>
{
... inside some method
T myT;
U myU;
IGenericInterface<T,U> myThing = new MyClass<T,U>();
myT = myThing.Convert(myU);
}
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());
}