Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/277.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 确定类型等价性_C#_Types_Interface - Fatal编程技术网

C# 确定类型等价性

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

在C#(我使用的是.NET4.5,但要求更一般)中是否可以确定泛型类型的两个实现在功能上是否等效

作为需求示例,假设我有一个
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());
    }