MSUnity - Регистрация типов - Общий абстрактный класс - PullRequest
0 голосов
/ 20 января 2012

Я только что реализовал шаблон Translator, о котором говорилось здесь и здесь вот так ...

Интерфейс ITranslator ...

public interface ITranslator
{
    bool CanTranslate(Type targetType, Type sourceType);
    bool CanTranslate<TTarget, TSource>();
    object Translate(Type targetType, object source);
    TTarget Translate<TTarget>(object source);
}

Translator.cs ...

public abstract class Translator<TBusinessEntity, TServiceEntity> : ITranslator where TBusinessEntity : class
                                                                                where TServiceEntity : class
{
    public bool CanTranslate(Type targetType, Type sourceType)
    {
        return (targetType == typeof(TBusinessEntity) && sourceType == typeof(TServiceEntity)) ||
               (targetType == typeof(TServiceEntity) && sourceType == typeof(TBusinessEntity)); 
    }

    public bool CanTranslate<TTarget, TSource>()
    {
        return CanTranslate(typeof (TTarget), typeof (TSource));
    }

    public TTarget Translate<TTarget>(object source)
    {
        return (TTarget)Translate(typeof(TTarget), source);
    }

    public object Translate(Type targetType, object source)
    {
        if (targetType == typeof(TBusinessEntity))
            return ServiceToBusiness((TServiceEntity)source);

        if (targetType == typeof(TServiceEntity))
            return BusinessToService((TBusinessEntity)source);
        throw new System.ArgumentException("Invalid type passed to Translator", "targetType");  
    }

    protected abstract TServiceEntity BusinessToService(TBusinessEntity value);
    protected abstract TBusinessEntity ServiceToBusiness(TServiceEntity value);
    protected abstract List<TServiceEntity> BusinessToService(List<TBusinessEntity> valueList);
    protected abstract List<TBusinessEntity> ServiceToBusiness(List<TServiceEntity> valueList);
}

Вот мой класс StudentFeeTranslator, который реализует абстрактные методы Translator ...

public class StudentFeeTranslator : Translator<StudentFee, StudentFeeType>
{
    #region Overrides of Translator<StudentFee,StudentFeeType>

    protected override StudentFeeType BusinessToService(StudentFee value)
    {
        return new
            StudentFeeType
                   {
                        StudentFeeId = value.StudentFeeRefId,
                        FeeId = value.FeeRefId,
                        StudentId = value.StudentRefId,
                        SchoolId = value.SchoolRefId,
                        FeeDate = value.AssessmentDate,
                        FeeAmount = value.AssessmentAmount,
                        Balance = value.UnpaidBalance,
                        FeeTypeId = value.FeeType,
                        Description = value.FeeDescription
                    };
    }

    protected override StudentFee ServiceToBusiness(StudentFeeType value)
    {
        return new
            StudentFee
                   {
                        StudentFeeRefId = value.StudentFeeId,
                        FeeRefId = value.FeeId,
                        StudentRefId = value.StudentId,
                        SchoolRefId = value.SchoolId,
                        AssessmentDate = value.FeeDate,
                        AssessmentAmount = value.FeeAmount,
                        UnpaidBalance = value.Balance,
                        FeeType = (Byte)value.FeeTypeId,
                        FeeDescription = value.Description
                    };
    }

    protected override List<StudentFeeType> BusinessToService(List<StudentFee> valueList)
    {
        return valueList.Select(BusinessToService).ToList();
    }

    protected override List<StudentFee> ServiceToBusiness(List<StudentFeeType> valueList)
    {
        return valueList.Select(ServiceToBusiness).ToList();
    }

    #endregion
}

Следующим является мой класс StudentFeeService за вычетом ненужных методов.Обратите внимание на свойство Translator, помеченное для внедрения ...

public partial class StudentFeeService : IStudentFeeService
{
    #region Public Members

    [Dependency]
    public ITranslator Translator { get; set; }

    #endregion

    #region Private Methods

    private List<StudentFeeType> ConvertStudentFeeListToListOfStudentFeeTypes(List<StudentFee> studentFees)
    {
        return Translator.Translate<List<StudentFeeType>>(studentFees);
    }

    #endregion
}

Наконец, вот фрагмент кода моей попытки зарегистрировать класс Translator в моем контейнере Unity ...

container.RegisterType(typeof (ITranslator), typeof (Translator<,>));

Эта попытка не удалась.У меня вопрос, как я могу зарегистрировать общий абстрактный класс в контейнере Unity?К вашему сведению, я использую MSUnity 2.0.

1 Ответ

1 голос
/ 20 января 2012

Вы пытаетесь сопоставить неуниверсальный интерфейс с открытым универсальным типом. Как Unity (или любой другой контейнер) может угадать, нужна ли вашему сервису StudenFeeTranslator или RentalFeeTranslator? Оба реализуют ITranslator, и это все, что может видеть контейнер.

Вы можете зарегистрировать все ваши конкретные реализации ITranslator, дав им индивидуальные имена. Это то, что поддерживают все контейнеры. А затем заставьте Unity внедрить эту конкретную зависимость в свойство Translator вашего сервиса. Что-то вроде

container.RegisterType(typeof(ITranslator), typeof(StudentFeeTranslator), "StudentFee");
container.RegisterType(typeof(ITranslator), typeof(RentalFeeTranslator), "RentalFee");
container.RegisterType(typeof(IStudentFeeService), typeof(StudentFeeService), 
  new InjectionProperty("Translator", new ResolvedParameter<ITranslator>("StudentFee")));

Хотя это много повторяющегося кода.

Unity не поставляется с готовыми соглашениями о регистрации. Но проект TecX содержит усовершенствованный механизм конфигурации, который позволит вам сделать что-то вроде этого:

ConfigurationBuilder builder = new ConfigurationBuilder();
builder.Scan(
  scanner =>
    {
      scanner.AddAllImplementationsOf(typeof(ITranslator);
      scanner.AssembliesFromApplicationBaseDirectory();
    });
container.AddExtension(builder);

Здесь регистрируются все реализации ITranslator с именем реализующего класса (например, имя для StudentFeeTranslator будет StudentFeeTranslator) за один раз.

Если вы сделаете свой интерфейс универсальным, его будет проще внедрить в свойство. Совпадение ITranslator<X, Y> с его реализацией не представляет особой сложности.

...