Универсальный <T>, как брошенный?

У меня есть базовый класс "продукта", некоторые другие классы "ProductBookDetail", "ProductDVDDetail" наследовались этому классу. Я использую класс ProductService для создания операции на этих классах. Но, я должен сделать некоторую проверку в зависимости от типа (ISBN для Книги, языки для DVD). Я хотел бы знать лучший способ бросить значение "productDetail", я получаю в SaveOrupdate. Я попробовал GetType () и бросил с (ProductBookDetail)productDetail но это не работа.

Спасибо,

var productDetail = new ProductDetailBook() { .... };
var service = IoC.Resolve<IProductServiceGeneric<ProductDetailBook>>();
service.SaveOrUpdate(productDetail);

var productDetail = new ProductDetailDVD() { .... };
var service = IoC.Resolve<IProductServiceGeneric<ProductDetailDVD>>();
service.SaveOrUpdate(productDetail);


public class ProductServiceGeneric<T> : IProductServiceGeneric<T>
{
    private readonly ISession _session;
    private readonly IProductRepoGeneric<T> _repo;
    public ProductServiceGeneric()
    {
        _session = UnitOfWork.CurrentSession;
        _repo = IoC.Resolve<IProductRepoGeneric<T>>();
    }
    public void SaveOrUpdate(T productDetail)
    {            
        using (ITransaction tx = _session.BeginTransaction())
        {
            //here i'd like ot know the type and access properties depending of the class
            _repo.SaveOrUpdate(productDetail);
            tx.Commit();
        }
    }
}
6
задан Kris-I 16 March 2010 в 06:58
поделиться

7 ответов

Нееееет

Если у вас нет общих свойств ( как указано в контракте общего интерфейса), тогда у вас должна быть объявлена ​​общая функция в интерфейсе, который вызывается SaveOrUpdate для обработки этого

Каждый экземпляр общего интерфейса (ProductDetailBook, productDetail и т. д.) будет определять эту функцию по-разному, как того требует " // здесь я не хотел бы знать тип и свойства доступа в зависимости от класса "

Вы извлекаете код конкретного класса и помещаете его в общую функцию, это начало спагетти-кода

Это один из множество причин НЕ иметь общих служб

3
ответ дан 17 December 2019 в 00:07
поделиться

Возможно, вам следует вывести рефакторинг кода следующим образом:

abstract class Product 
{
   public abstract bool CheckProduct();
}
class ProductBookDetail : Product
{
   public override bool CheckProduct()
   {
      //Here we can check ProductBookDetail
   }
}

class ProductDetailDVD : Product
{
   public override bool CheckProduct()
   {
      //Here we can check ProductDetailDVD
   }
}

public class ProductServiceGeneric<T> : IProductServiceGeneric<T> where T : ProductDetail
{
    public void SaveOrUpdate(T product)
    {
       if (!product.CheckProduct())
       {
           //product checking failes. Add necessary logic here
       }
    }
}

Этот код гораздо больше подходит для ООП. Он намного проще, он более расширяемый и менее подверженный ошибкам.

P.S. Не забывайте про S.O.L.I.D.

0
ответ дан 17 December 2019 в 00:07
поделиться

Я не хочу быть критичным, но этот образец кажется мне плохим.

Я слышал, как другие говорят, что если вы берете тип в универсальном методе, то, скорее всего, вы делаете что-то не так.

Я бы реорганизовал ваш код, объявив метод базового класса, чтобы помочь с методом SaveOrUpdate , а затем производные классы переопределили этот метод. Теперь, когда вы вызываете метод базового класса в универсальном методе, вы получаете имплементацию производных классов

3
ответ дан 17 December 2019 в 00:07
поделиться

Если вам нужно знать о полях или свойствах типа для «сохранения или обновления», вы можете использовать отражение. Таким образом, класс останется по-настоящему универсальным.

Если в вашем методе SaveOrUpdate вы хотите написать постоянно расширяющийся переключатель, эквивалентный:

if (it's type A) { deal with type A }
else if (it's type B) { deal with type B }
... and so on

, значит, вы делаете это «неправильно». Этот класс не является универсальным по параметру типа. Он работает только с определенным набором указанных вами типов. Я говорю «неправильно» в кавычках, потому что в некоторых ситуациях это может быть лучше, чем доступные альтернативы, но это нежелательно. Если у вас есть запасной вариант для всех других типов, поэтому он всегда работает, тогда, возможно, будет неплохим способом создать особые случаи для определенных типов.

Однако вы можете выполнить такой тест или кастинг. С параметром неограниченного типа, T , вам нужно сначала привести его к объекту :

var eitherStringOrNull = (string)((object)somethingOfTypeT);

С ключевым словом as вам не понадобится это дополнительное приведение в объект .

var eitherStringOrNull = somethingOfTypeT as string;
if (eitherStringOrNull != null)
{
    .. it was a string, so we can use it as such
}

Но даже лучше, если существует общий базовый класс, ProductDetail , для всех видов классов сведений о продукте, тогда используйте его в качестве ограничения для T :

public class ProductServiceGeneric<T> : IProductServiceGeneric<T>
       where T : ProductDetail

I думаю, что при этом рекомендуется использовать более значимое имя для параметра типа, например TProductDetail .

Если вы это сделаете, то компилятор должен позволить вам «выполнить приведение» к чему-то, производному от ProductDetail , без необходимости сначала выполнять приведение к объекту .

3
ответ дан 17 December 2019 в 00:07
поделиться

Используйте:

if(productDetail is ProductDetailBook)
{
...
...
}

и аналогично для других.

-2
ответ дан 17 December 2019 в 00:07
поделиться

Если я понимаю ваш вопрос, вы пытаетесь определить, какой у вас производный класс от функции, возвращающей базовый класс. Вам необходимо использовать оператор IS

, вы можете увидеть, как использовать оператор ниже.

class Base
{
}

class AB : Base
{

}
class AC : Base { }

class Program
{
   static Base GetObject()
   {
       return null;
   }
   static void Main(string[] args)
   {
       Base B = GetObject();
       if (B is AB)
       {
          AB DevClass =(AB) B;
       }
   }


}

}

0
ответ дан 17 December 2019 в 00:07
поделиться

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

Если вы много работаете с дженериками, прочтите Билла Вагнерса «Более эффективный C #», чтобы узнать об альтернативных способах более аккуратного решения этой проблемы.

public void SaveOrUpdate(T productDetail) 
{             
    using (ITransaction tx = _session.BeginTransaction()) 
    { 
        ProductDetailBook bookDetail = productDetail as ProductDetailBook;
        if (bookDetail != null)
           _repo.SaveOrUpdate(bookDetail); 
        tx.Commit(); 
    } 
} 
0
ответ дан 17 December 2019 в 00:07
поделиться
Другие вопросы по тегам:

Похожие вопросы: