Класс Wrapper, упаковывающий несколько типов и шаблон композиции - PullRequest
0 голосов
/ 05 ноября 2018

У меня есть следующий класс-оболочка, который оборачивает TypeA, TypeB и TypeC.

class Wrapper
{
    class TypeA {get;set;}
    class TypeB {get;set;}
    class TypeC{get;set;}
}

Теперь код вызывающего абонента не очень хорош из-за этого. Как я должен определить на основе различных типов, как это:

Wrapper wrapper = new Wrapper(TypeA);

if (wrapper.TypeA != null && wrapper.TypeA.SomeProperty != null)
{
    return wrapper.TypeA.SomeProperty;
}

if (wrapper.TypeB != null && wrapper.TypeB.SomeProperty != null)
{
    return wrapper.TypeB.SomeProperty;
}

Wrapper cwrapper = new Wrapper(TypeA, TypeB);

if (wrapper.TypeA == null && wrapper.TypeB != null && wrapper.TypeB.SomeProperty != null)
{
    return wrapper.TypeB.SomeProperty;
}

Как видите, код вызывающего абонента должен также проверять множество комбинаций TypeA и TypeB и TypeC. Я просто думал использовать композицию и выставить стратегию или свойство, которое даст мне желаемый объект, такой как:

wrapper.As<TypeA>() или что-то. Любое предложение, как избежать этого многократных проверок со стороны вызывающего абонента?

Ответы [ 3 ]

0 голосов
/ 05 ноября 2018

Я бы посоветовал использовать некоторые защитные выражения в вашем конструкторе и некоторые свойства только для чтения, чтобы привести в порядок все это

class Wrapper
{
    public TypeA A {get;}
    public TypeB B {get;}
    public TypeC C {get;}

  public Wrapper(TypeA A, TypeB B, TypeC C)
  {
   this.A = A ?? throw new ArgumentNullException(nameof(A));
   this.B = B ?? throw new ArgumentNullException(nameof(B));
   this.C = C ?? throw new ArgumentNullException(nameof(C));
  }
}

Теперь, если кто-то не сделал что-то глупое с отражением, ваши свойства A, B, C не могут быть нулевыми. Так что вам не нужно проверять ноль.

Затем вы можете использовать оператор объединения нулей, чтобы привести в порядок последние биты

wrapper.A.someProperty ?? string.Empty
0 голосов
/ 05 ноября 2018

Как вы и предлагали, я бы использовал тип удобного метода приведения. Примерно так:

class Wrapper {
    bool TryGet<T> (out T wrappedObj) {
        if (typeof(T) == ClassA.GetType()) {
            wrappedObj = objA;
        }
        //...
        return wrappedObj != null;
    }

    // or
    bool TryGet<T,U>(Func<U> propGetter, out U prop) {
        if (TryGet<T>(out T wrappedObj)) {
            prop = propGetter(wrappedObj);
            return true;
        }
        prop = default(U); 
        return false;
    }
}

if (wrapper.TryGet<ClassA>(out ClassA obj)) {
//...
}

//or

if (wrapper.TryGet<ClassA, String>(aObj =>  aObj?.SomeProperty, out String prop) {

}
0 голосов
/ 05 ноября 2018

Почему? Вы используете вид Adapter Pattern и ваш класс должен выглядеть как

class Wrapper
{
    public TypeA A {get;set;}
    public TypeB B {get;set;}
    public TypeC C{get;set;}

  public Wrapper(TypeA A, TypeB B, TypeC C)
  {
   this.A = A;
   // rest initialization
  }
}

Теперь вы можете просто сказать

Wrapper w = new Wrapper(new TypeA(), ...);
w.A.SomeProperty;

Опять же, вместо этого условия проверки нуля if вы можете использовать оператор Null Propagation , например

wrapper?.TypeA?.SomeProperty;

Вы можете использовать оператор Null Coalesce вместе, чтобы вернуть значение свойства по умолчанию в случае, если свойство равно null

wrapper?.TypeA?.SomeProperty ?? string.Empty;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...