2010-11-02 73 views
0

我有第三方设计糟糕的图书馆,我必须使用。
它拥有各种类型它与中,我们会打电话给他们SomeType1SomeType2
没有这些类型都有一个共同的基类,但都具有不同的返回类型一个名为Value属性。
我想要做的就是能够Mixin这个类,所以我可以打电话someType1Instance.ValuesomeType2Instance.Value,而不必关心它的结构类型和不关心返回类型是什么(我可以使用object)。
所以我的代码目前是:没有基类问题,在这种特殊情况下如何使用Castle.DynamicProxy Mixin?

public interface ISomeType<V> 
{ 
    V Value {get; set;} 
} 

public interface ISomeTypeWrapper 
{ 
    object Value { get; set; } 
} 

public class SomeTypeWrapper<T> : ISomeTypeWrapper 
    where T : ISomeType<???> 
{ 
    T someType; 

    public SomeTypeWrapper(T wrappedSomeType) 
    { 
    someType = wrappedSomeType 
    } 

    public object Value 
    { 
    get { return someType.Value; } 
    set { someType.Value = value != null ? value : default(T); } 
    } 
} 

public class SomeType1 
{ 
    public int Value { get; set; } 
} 

public class SomeType2 
{ 
    public string Value { get; set; } 
} 

的问题是,我不知道是什么牛逼可能直到运行时由于这样的事实,我得到的对象的字典。

我可以迭代字典并使用反射来创建一个运行时的SomeWrapperType,但我想避免它。

如何将SomeType的concreate类型混入ISomeType?
我怎么知道V型参数是什么? (希望我有像C++一样的typedefs和decltype)

我怎样才能以最少的反射使用Mixin这些具有接口/基类的类?

+0

有多少类型,我们在谈论什么?什么是第三方api? – Bronumski 2010-11-02 15:54:11

+0

13-14,microsoft dynamics crm。 – 2010-11-02 15:56:49

回答

1

您可以尝试温莎的Duck Typing Extensions。这意味着您需要注册每个类型。

container 
    .Register(Component.For(typeof(SomeType1)).Duck<ISomeType>()) 
    .Register(Component.For(typeof(SomeType2)).Duck<ISomeType>()); 

如果名称相似,您可以使用linq和寄存器AllTypes语法来减少代码。

或者在短期内创建一个工厂,它可以返回您需要的对象,为每个类型实现一个具体对象。不,你正在使用的界面,您可以在日后取出工厂,并与影响最小别的东西替代它:

public class SomeTypeWrapperFactory 
{ 
    public ISomeType<int> CreateWrapper(SomeType1 someType1) 
    { 
     return new SomeType1Wrapper(someType1); 
    } 

    public ISomeType<string> CreateWrapper(SomeType2 someType2) 
    { 
     return new SomeType2Wrapper(someType2); 
    } 
} 

public class SomeType1Wrapper : ISomeType<int> { ... } 
public class SomeType2Wrapper : ISomeType<int> { ... } 

不管你如何实现包装的,可以单独或使用神象类,你有能力改变包装的完成方式并保持代码的其余部分清洁。

+0

“显然,DeftTech生成的代理不能由DynamicProxy代理......所以不要试图为这些组件定义任何拦截器!再一次,最佳解决方案是使用DynamicProxy实现适当的鸭子输入”。这是一个问题,我计划拦截方法调用。 – 2010-11-02 16:32:08

+0

尝试了工厂方法,因为我不知道我的对象的类型是什么,直到运行时才得到我的字典。 – 2010-11-02 18:06:19

+0

这是我得到的最接近的。我将此标记为接受的答案。 – 2010-11-16 10:51:36

1

为什么SomeTypeWrapper而不是SomeObjectWrapper?

public class SomeObjectWrapper : ISomeType 
{ 
    Object _someObject; 
    PropertyInfo _valuePropertyInfo; 

    public SomeObjectWrapper(Object wrappedSomeObject) 
    { 
     _someObject = wrappedSomeObject; 
     _valuePropertyInfo = _someObject.GetType().GetProperty("Value", System.Reflection.BindingFlags.Public); 
    } 

    public object Value 
    { 
     get { return _valuePropertyInfo.GetValue(_someObject, null); } 
     set { _valuePropertyInfo.SetValue(_someObject, value, null); } 
    } 
} 
+0

这是一种有效的方法,但如果可能的话,我真的很乐意不使用反射。如果可能的话,我宁愿将其混入一个通用界面。 – 2010-11-02 16:03:09

0

编辑使用LinFu的.NET 3.5 您可以使用LinFu而不是Castle。然而,无论如何,你会使用反射,无论是Castle还是Linfu的DynamicProxy,都只能隐藏在库的内部,而不是暴露在代码中。因此,如果您的要求避免使用反射是出于性能考虑,那么使用此解决方案就不会真正避免它。 在这种情况下,我会亲自选择Orsol的解决方案。

但是:这里有一个LinFu的ducktyping的例子。

public interface ISomeType { 
    object Value{get; set;} 
} 

public class SomeType1 
{ 
    public int Value { get; set; } 
} 

public class SomeType2 
{ 
    public string Value { get; set; } 
} 

public class SomeTypeWrapperFactory 
{ 

    public static ISomeType CreateSomeTypeWrapper(object aSomeType) 
    { 
     return aSomeType.CreateDuck<ISomeType>(); 
    }   
} 


class Program 
{ 
    public static void Main(string[] args) 
    { 
     var someTypes = new object[] { 
      new SomeType1() {Value=1}, 
      new SomeType2() {Value="test"} 
     }; 


     foreach(var o in someTypes) 
     { 
      Console.WriteLine(SomeTypeWrapperFactory.CreateSomeTypeWrapper(o).Value); 
     } 
     Console.ReadLine(); 
    } 
} 

既然你不知道SOMETYPE的,直到运行时,我不会用混入的类型,但访问者模式(我知道这并没有回答关于如何使用混入了这个问题,但我只是认为我会投入我的2美分)。

在.NET 4中使用动态Bradley Grainger's post here使用C#4的动态关键字来实现访问者模式。 在你的情况,阅读完所有的“价值”从SOMETYPE的字典特性可以工作是这样的:

public class SomeType1 
{ 
    public int Value { get; set; } 
} 

public class SomeType2 
{ 
    public string Value { get; set; } 
} 

public class SomeTypeVisitor 
{ 
    public void VisitAll(object[] someTypes) 
    { 
     foreach(var o in someTypes) { 
      // this should be in a try-catch block 
      Console.WriteLine(((dynamic) o).Value); 
     } 

    } 
} 
class Program 
{ 
    public static void Main(string[] args) 
    { 
     var someTypes = new object[] { 
      new SomeType1() {Value=1}, 
      new SomeType2() {Value="test"} 
     }; 

     var vis = new SomeTypeVisitor(); 

     vis.VisitAll(someTypes);    
    } 
} 
+0

我无法使用C#4.0。我们的平台是3.5。 – 2010-11-04 17:53:08

+0

使用LinFu的DuckTyping添加了一个解决方案 – 2010-11-05 09:13:32

相关问题