泛型:如何检查T的确切类型,没有T的对象

时间:2010-10-31 17:57:58

标签: c# generics

如何在没有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时,我实际上没有为Casino和Drugstore创建实际对象,我只是将其作为类的泛型类型约束传递。我只需要确切知道我通过哪个类型的BusinessManager来了解要实例化的Type究竟是什么。感谢...

PS:我不想为Casino和Drugstore创建单独的特定BusinessManager。

您也可以对设计发表评论..谢谢..

附加:如果类Casino和DrugStore是抽象类,那该怎么办?)

8 个答案:

答案 0 :(得分:12)

你可以写

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();
    }
}

答案 1 :(得分:9)

你应该做

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

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

答案 2 :(得分:2)

我不知道C#语法,但是不可能这样做:

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

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

答案 3 :(得分:2)

由于其他人已经对你的第一个问题给出了各种答案,我想谈谈第二个问题:设计。

<强> 1。 BusinessManager

的作用

示例中BusinessManager类的实际角色不太清楚。由于这个类是通用的,并且它不应该关注T的实际类型,因此它只是在Business类和程序的其余部分之间添加另一个不必要的层。

换句话说,你可以简单地使用:

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

答案 4 :(得分:2)

由于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;
    }

答案 5 :(得分:1)

您可以这样做:

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

答案 6 :(得分:1)

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());

你使用你的方式将失去封装

答案 7 :(得分:1)

在VB.net中,您可以在泛型类型参数上使用GetType伪函数来获取反射Type对象。我猜C#应该有一个等价物。如果由于某种原因你不能使用类似的东西,你可以创建一个包含所需类型的0个元素的数组,然后检查该数组的类型。这可能比实例化未知类型的元素便宜。