2013-02-21 74 views
0

我已经提供了两个库,每个库都有自己的命名空间,它们对于api的请求部分具有相同的类结构,但是具有不同的响应。两个命名空间具有相同的类,如何防止必须编写两个相同的函数?

我想编写一个函数,可以处理与其名称空间类型无关的两个请求(我尝试过泛型但未能创建解决方案)。

这里是什么,我试图做一个例子:

public void Function1() 
{ 
    Namespace1.MyType type1 = new Namespace1.MyType1(); 
    type1.InnerType = new Namespace1.MyType2(); 

    type1.PerformMethod1(); 
} 

public void Function2() 
{ 
    Namespace2.MyType type1 = new Namespace2.MyType1(); 
    type1.InnerType = new Namespace2.MyType2(); 

    type1.PerformMethod1(); 
} 

我试图通过以下方式在方法级别使用泛型:

public void Function1<TType1, TType2>() 
    where TType1: NamesSpace1.Type1, NamesSpace2.Type1, new() 
    where TType2: Namespace1.Type2. Namespace2.Type2(), new() 
{ 
    TType1 type1 = new TType1(); 
    type1.InnerType = new TType2(); 

    type1.PerformMethod1(); 
} 

然而,.NET确实不允许泛型的这种限制。 关于如何创建通用函数的任何建议都非常棒。

谢谢

+0

当然你可以用命名空间调用它? Cplusplus是这样的情况 – 2013-02-21 11:38:16

回答

1

泛型的.Net真的不这样的。

我认为最好的方法是创建一个通用接口,并以某种方式适应库类。问题是如何做到这一点。

如果有问题的类型不密封,并在创建它的实例自己,那么你可以创建一个派生类实现该接口,将由继承的方法来自动执行:

interface IMyType 
{ 
    object InnerType { get; set; } 
    void PerformMethod1(); 
} 

class Namespace1MyTypeWithInterface : Namespace1.MyType, IMyType 
{} 

这假定两种类型实际上是相同的。例如,如果InnerType的类型各不相同,则情况变得更加复杂。解决这个问题的一种方法是使接口在属性类型中是通用的。

如果以前的解决方案不适合您,则可以为每个名称空间创建适配器类。两个适配器将再次共享相同的接口,并且他们会将每个调用委托给实际类型的实例。

class Namespace1MyTypeAdapter : IMyType 
{ 
    private readonly Namespace1.MyType m_adapted; 

    public Namespace1MyTypeAdapter(Namespace1.MyType adapted) 
    { 
     m_adapted = adapted; 
    } 

    public object InnerType 
    { 
     get { return m_adapted.InnerType; } 
     set { m_adapted.InnerType = value; } 
    } 

    public void PerformMethod1() 
    { 
     m_adapted.PerformMethod1(); 
    } 
} 

这是很多重复的代码,但你写了一次,然后你可以用同样的方式使用两个类。

还有一种选择是使用dynamic或反射。

+0

对于接口和实现它的派生类型的想法+1。 – 2013-02-21 12:24:58

2

简短的回答是:你不能。

C#(或.NET for the matter)不支持“Structural Subtyping”,使这两个类完全分离,尽管它们具有相同的成员。

然而,您可以使用dynamic关键字,但是您将失去所有编译时类型的安全性。

publiv void Function(dynamic type1) 
{ 
    type1.PerformMethod1(); 
} 

你仍然要创建的type1type2两种不同的情况下,这样你就不会真正得到很多在这里。

具有基本相同的缺点另一种可能的解决方案是使用反射创建类型:

public void Function(string assemblyName, string namespace) 
{ 
    var type1Name = namespace + ".Type1, " + assemblyName; 
    var type2Name = namespace + ".Type2, " + assemblyName; 
    dynamic type1 = Activator.CreateInstance(Type.GetType(type1Name)); 
    dynamic type2 = Activator.CreateInstance(Type.GetType(type1Name)); 
    type1.InnerType = type2; 
    type1.PerformMethod1(); 
} 

而第三种解决方案是使用仿制药只能用new()约束能够更轻松地创建实例并使用运行时类型检查来确保只使用了允许的类型。同样,这有相同的缺点其他两个解决方案:没有编译时类型安全:

public void Function1<TType1, TType2>() 
    where TType1 : new() 
    where TType2 : new() 
{ 
    if(typeof(TType1) != typeof(Namespace1.MyType1) || 
     typeof(TType1) != typeof(Namespace2.MyType1) || 
     typeof(TType2) != typeof(Namespace1.MyType2) || 
     typeof(TType2) != typeof(Namespace2.MyType2)) 
     throw new ArgumentException(...); 

    // .NET 4: 
    dynamic type1 = new TType1(); 
    dynamic type2 = new TType2(); 
    // Pre .NET 4: 
    // var type1 = new TType1(); 
    // var type2 = new TType2(); 

    // .NET 4: 
    type1.InnerType = type2; 
    // Pre .NET 4: 
    // type1.GetType().GetProperty("InnerType").SetValue(type1, type2); 

    // .NET 4: 
    type1.PerformMethod1(); 
    // Pre .NET 4: 
    // type1.GetType().GetMethod("PerformMethod1").Invoke(type1, new object[0]); 
} 
+0

谢谢丹尼尔。我担心这将是答案。无论如何,动态是不可行的,因为我们还没有上.net 4.0。 – 2013-02-21 11:51:41

+0

@BarryMills:请参阅更新,我又添加了一个建议。 – 2013-02-21 11:56:35

+0

@BarryMills你应该总是在你的问题中提到类似的东西。 – svick 2013-02-21 12:06:16

相关问题