Нет проблем с базовым классом, как использовать Castle.DynamicProxy Mixin в данном конкретном случае? - PullRequest
0 голосов
/ 02 ноября 2010

У меня есть сторонняя плохо спроектированная библиотека, которую я должен использовать.
У него есть все виды типов, с которыми он работает, мы будем называть их SomeType1 , SomeType2 и т. Д.
Ни один из этих типов не имеет общего базового класса, но у всех есть свойство с именем Value с другим типом возвращаемого значения.
Все, что я хочу сделать, - это иметь возможность смешивать этот класс, так что я буду в состоянии вызывать someType1Instance.Value и someType2Instance.Value, не обращая внимания на то, какой это конкретный тип, и не заботясь о том, какой тип возврата (я могу использовать 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, до времени выполнения из-за того, что я получаю словарь объектов.

Я могу перебрать словарь и использовать отражение для создания SomeWrapperType во время выполнения, но я бы хотел этого избежать.

Как я могу смешать конкретный тип SomeType с ISomeType?
Как я могу узнать, что такое параметр типа V? (если бы у меня были typedefs и decltype как в c ++)

Как я могу с минимальным использованием отражения возможно смешивать эти классы с интерфейсом / базовым классом?

Ответы [ 3 ]

1 голос
/ 02 ноября 2010

Вы можете попробовать 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> { ... }

Независимо от того, как вы реализуете обертку, будьте индивидуальны или используйте богоподобный класс, у вас есть возможность изменить способ обертывания и сохранить оставшуюся часть кода в чистоте.

1 голос
/ 02 ноября 2010

Почему 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 голосов
/ 04 ноября 2010

Отредактировано В .NET 3.5 с использованием LinFu Вы можете использовать LinFu вместо Castle.Тем не менее, вы все равно будете использовать отражение, как с Каслом, так и с DynamicProxy Линфу, только скрытые в кишках библиотек вместо того, чтобы раскрываться в вашем коде.Поэтому, если ваше требование избегать использования рефлексии не связано с проблемами производительности, вы бы не стали этого делать с этим решением.В этом случае я бы лично выбрал решение Орсола.

Однако: вот пример с утиным вводом LinFu.

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 с использованием динамического См. пост Брэдли Грейнджера здесь об использовании динамического ключевого слова c # 4 для реализации шаблона посетителя.В вашем случае чтение всех свойств «Value» из вашего словаря 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);            
    }
}
...