Generics: Как проверить точный тип T, без объекта для T

Как я могу проверить/оценить точный тип T без объекта для T. Я знаю, что мой вопрос может быть запутанным, но рассмотрим это...

 public abstract class Business
    {
        public abstract string GetBusinessName();
    }

    public class Casino : Business  
    {
        public override string GetBusinessName()
        {
            return "Casino Corp";
        }
    }

    public class DrugStore : Business 
    {
        public override string GetBusinessName()
        {
            return "DrugStore business";
        }
    }


    public class BusinessManager<T> where T : Business
    {
        private Casino _casino;
        private DrugStore _drugStore;

        public string ShowBusinessName()
        {
            string businessName;
            if (T == Casino) // Error: How can I check the type?
            {
                _casino = new Casino();
                businessName = _casino.GetBusinessName();
            }
            else if (T == DrugStore) // Error: How can I check the type?
            {
                _drugStore = new DrugStore();
                businessName = _drugStore.GetBusinessName();
            }

            return businessName;

        }
    }

Я просто хочу иметь что-то подобное на клиенте.

    protected void Page_Load(object sender, EventArgs e)
    {
        var businessManager = new BusinessManager<Casino>();
        Response.Write(businessManager.ShowBusinessName());

        businessManager = new BusinessManager<DrugStore>();
        Response.Write(businessManager.ShowBusinessName());
    }

Обратите внимание, что я фактически не создал фактический объект для Казино и Аптеки, когда я вызываю BusinessManager, я просто передаю его как ограничение общего типа класса. Мне просто нужно точно знать, какой тип я передаю BusinessManager, чтобы узнать , что именно Тип для создания экземпляра. Спасибо...

PS: Я не хочу создавать отдельный конкретный BusinessManager для казино и аптеки..

Вы также можете прокомментировать дизайн.. спасибо..

ДОПОЛНИТЕЛЬНО: и что, если класс Casino и DrugStore - АБСТРАКТНЫЙ КЛАСС =)

Ответ 1

Вы должны сделать

public class BusinessManager<T> where T : Business, new()
...

T _business = new T();
string businessName = _business.GetBusinessName();
return businessName;

Ответ 2

Вы можете написать

if(typeof(T) == typeof(Casino))

но на самом деле этот тип логики является запахом кода.

Здесь один из способов:

public class BusinessManager<T> where T : Business, new() {
    private readonly T business;
    public BusinessManager() {
        business = new T();
    }
}

но лично я бы предпочел

public class BusinessManager<T> where T : Business {
    private readonly T business;
    public BusinessManager(T business) {
        this.business = business;
    }

    public string GetBusinessName() { 
        return this.business.GetBusinessName();
    }
}

Ответ 3

Я не знаю синтаксиса С#, но это невозможно сделать:

public class BusinessManager<T> where T : Business, new()
    {
        private T _business;

        public string ShowBusinessName()
        {
            string businessName;
            _business = new T();
            return _business.GetBusinessName();
        }
    }

Ответ 4

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

1. Роль BusinessManager

Фактическая роль класса BusinessManager в вашем примере не слишком ясна. Поскольку этот класс является общим, и он не должен касаться фактического типа T, то он не делает ничего, кроме добавления лишнего слоя между бизнес-классом и остальной частью программы.

Другими словами, вы можете просто использовать:

Business casino = new Casino();
Response.Write(casino.GetBusinessName());

Business drugStore = new DrugStore();
Response.Write(drugStore.GetBusinessName());

Обертка этого в другом родовом классе вам не поможет. С другой стороны, если вы хотите иметь некоторые общие функции для всех этих классов, вы можете либо добавить их непосредственно в абстрактный класс, либо извлечь интерфейс и создать методы расширения для этого интерфейса.

2. Использование свойств для геттеров

Во-вторых, использование свойства более уместно, если у вас есть простой метод getter. Другими словами, вы должны заменить метод GetBusinessName() на свойство Name (я также пропустил "Бизнес" из имени, потому что это необязательно:

public interface IBusiness
{
    string Name { get; }
}

public abstract class Business : IBusiness
{
    public abstract string Name { get; }
}

public class Casino : Business  
{
    public override string Name
    {
        get { return "Casino Corp"; }
    }
}

public class DrugStore : Business 
{
    public override string Name
    {
        get { return "DrugStore business"; }
    }
}

И тогда вы можете использовать его следующим образом:

IBusiness casino = new Casino();
Response.Write(casino.Name);

IBusiness drugStore = new DrugStore();
Response.Write(drugStore.Name);

Кроме того, вы можете видеть, что я ввел интерфейс IBusiness. Причина этого - позволить вам реализовать этот интерфейс более разнообразными способами. Прямо сейчас вы попытаетесь вывести все классы из абстрактного класса Business и попытаться извлечь как можно больше общих функций в абстрактном классе (что цель класса).

Но извлечение множества общих функций связано со стоимостью: всегда есть вероятность, что вам придётся создать класс, из которого не выводится из Business. Если вы получаете доступ ко всем этим методам с помощью интерфейса IBusiness, тогда другим частям вашей программы будет все равно, будет ли эта реализация получена из Business или нет.

Ответ 5

Так как GetBusinessName действительно относится к типу, а не к экземплярам типа, вы можете рассмотреть использование атрибута DescriptionAttribute (или собственный собственный атрибут BusinessNameAttribute) вместо переопределенного свойства и получить бизнес-имя BusinessManager из атрибута.

[Description("Casino Corp")]
public class Casino : Business  
{
}

Теперь вам больше не нужно создавать бизнес, чтобы получить его имя. Чтобы получить описание, вы используете:

    public string ShowBusinessName()
    {
        var attribute = Attribute.GetCustomAttribute(typeof(T), typeof(DescriptionAttribute)) as DescriptionAttribute;
        if (attribute == null)
            return "Unknown business";

        return attribute.Description;
    }

Ответ 6

Вы можете сделать что-то вроде этого:

if (typeof(T) == typeof(SomeType))
{
    // Same
}

Ответ 7

определите класс BusinessManager как ниже:

public class BusinessManager<T> where T : Business
{ 
    Business biz;
    public BusinessManager()
    {
        biz = new T();
    }

    public string ShowBusinessName()
    {
        return biz.GetBusinessName();
    }
}

и используйте его ниже:

    var businessManager = new BusinessManager<Casino>();
    Response.Write(businessManager.ShowBusinessName());

    var anotherBusinessManager = new BusinessManager<DrugStore>();
    Response.Write(businessManager.ShowBusinessName());

Способ использования вами потеряет инкапсуляцию

Ответ 8

В VB.net вы можете использовать псевдофункцию GetType для параметра общего типа, чтобы получить объект Type отражения. Я бы предположил, что С# должен иметь эквивалент. Если по какой-либо причине вы не можете использовать что-то подобное, вы можете создать массив из 0 элементов нужного типа, а затем проверить тип этого массива. Это, вероятно, будет дешевле, чем создание экземпляра неизвестного типа.