开发者

Generics: How to check the exact type of T, without object for T

开发者 https://www.devze.com 2023-01-23 09:19 出处:网络
How can i check/evaluate the exact type of T without an object for T. I know my question maybe confusing but consider this...

How can i check/evaluate the exact type of T without an object for T. I know my question maybe confusing but consider this...

 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;

        }
    }

I just want to have something like this on the client.

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

Notice that I actually didnt create the actual object for Casino and Drugstore when I call the BusinessManager, I just pass it as generic type constraint of the class. I just need to know exactly what Type i am passing BusinessManager to know what exactly the Type to instantiate. Thanks...

PS: I don't want to create separate specific BusinessManager for Casino and Drugstore..

You can also comment about the design.. thanks..

ADDITIONAL: and what if class Casino and DrugStore is an ABSTRACT CLASS =)


You can write

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

but really this type of logic is a code smell.

Here's one way around this:

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

but personally I'd prefer

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


You should do

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

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


I don't know about C# syntax, but is it not possible to do:

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

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


Since other guys have already shown various answers to your first question, I would like to address the second one: design.

1. Role of BusinessManager

Actual role of the BusinessManager class in your example is not too clear. Since this class is generic, and it shouldn't be concerned with the actual type of T, then it does nothing more than add another unnecessary layer between the Business class and the rest of the program.

In other words, you can simply use:

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

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

Wrapping this in another generic class doesn't help you a lot. On the other hand, if you want to have some common functionality for all these classes, you can either add it directly to your abstract class, or extract an interface and create extension methods for that interface.

2. Using properties for getters

Second thing, using a property is more appropriate when you have a simple getter method. In other words, you should replace GetBusinessName() method with a Name property (I also omitted the "Business" from the name because it is not necessary:

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"; }
    }
}

And then you can use it like this:

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

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

Also, you can see that I have introduced a IBusiness interface. The reason for doing so is to allow you to implement this interface in more diverse ways. Right now, you will try to derive all your classes from the abstract Business class, and try to extract as much of the common functionality in the abstract class (that's the purpose of the class).

But extracting lots of common functionality comes with a cost: there is always a possibility that you will come up with a need to create a class which isn't derived from Business. If you are accessing all these methods through the IBusiness interface, then other parts of your program won't care if that implementation is derived from Business or not.


Since GetBusinessName really applies to the type and not instances of the type, you might consider using DescriptionAttribute (or your own BusinessNameAttribute) instead of an overridden property and have your BusinessManager get the business name from the attribute.

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

Now you no longer need to instantiate the business just to gets its name. To get the description, you use:

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

        return attribute.Description;
    }


You can do something like this:

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


define a BusinessManager class as bellow:

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

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

and use it as bellow:

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

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

The way you using you will lost encapsulation


In VB.net you can use the GetType pseudo-function on a generic type parameter to get a reflection Type object. I would guess C# should have an equivalent. If for whatever reason you can't use something like that, you could create an array of 0 elements of the desired type, and then check the type of that array. That would probably be cheaper than instantiating an element of the unknown type.

0

精彩评论

暂无评论...
验证码 换一张
取 消