代码之家  ›  专栏  ›  技术社区  ›  the_drow

没有基类问题,在这个特殊的情况下如何使用Castle.DynamicProxy Mixin?

  •  0
  • the_drow  · 技术社区  · 14 年前

    我有一个设计糟糕的第三方图书馆,我必须使用。
    它有各种类型,我们称之为 , 某些类型2
    这些类型都不共享公共基类,但都有一个名为Value的属性,其返回类型不同。
    我想做的就是能够混合这个班,这样我就可以打电话了。 someType1Instance.Value someType2Instance.Value 不关心concreate类型是什么,也不关心return类型是什么(我可以使用 object ).

    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; }
    }
    

    问题是,由于我得到了一个对象字典,所以在运行时之前我不知道t是什么。

    我怎样才能把这种类型的类型混合到ISomeType?
    我怎么知道V型参数是什么?(希望我有typedefs和decltype,就像在c++中一样)

    我能怎样,在使用接口/基类的那些类中最少使用反射?

    3 回复  |  直到 14 年前
        1
  •  1
  •   the_drow    14 年前

    你可以试试 Duck Typing Extensions 为温莎。这意味着你需要注册你的每一种类型。

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

    或者在短期内创建一个工厂,它可以返回您需要的对象,为每种类型实现一个具体的对象。不,您使用的是接口,您可以稍后删除工厂并用其他影响最小的东西替换它:

    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> { ... }
    

    不管你是如何实现包装器的,你都可以独立地或者使用一个类似上帝的类,这样你就可以改变包装的方式,并保持代码的其余部分干净。

        2
  •  1
  •   Denis Palnitsky    14 年前

    为什么要用typewrapper而不是objectwrapper?

    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); }
        }
    }
    
        3
  •  0
  •   Paolo Falabella    14 年前

    编辑 那样的话,我个人会选择奥索的解决方案。

    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();
        }
    }
    

    因为直到运行时你不知道这些类型的类型,所以我不会使用MIXIN,而是访问者模式(我知道这并不能回答如何使用Mixin的问题,但我只是想把我的2分钱扔掉)。

    Bradley Grainger's post here 使用c#4的动态关键字实现访问者模式。 在您的例子中,从字典中读取某个类型的所有“Value”属性的工作方式如下:

    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);            
        }
    }