tags:

views:

226

answers:

8

Hi guys, 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 =)

+10  A: 

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();
    }
}
Jason
yeah, this is c++ish, is there any other way to do this? thanks
CSharpNoob
@CSharpNoob: Please see my edit.
Jason
thanks it works! :)
CSharpNoob
i prefer the first one with the new() constraint :)
CSharpNoob
@CSharpNoob: actually, this should be a better solution, because it allows you to use a derived class with any constructor signature. With new() constraint, you are *constrained* to using parameterless constructors.
Groo
@CSharpNoob: Notice that my solution works even for abstract `T`.
Jason
+1  A: 

You can do something like this:

if (typeof(T) == typeof(SomeType))
{
    // Same
}
Fara
+9  A: 

You should do

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

T _business = new T();
string businessName = _business.GetBusinessName();
return businessName;
Albin Sunnanbo
hmm.. ill try this approach..
CSharpNoob
Thanks guys for all your answers! but i gave the CHECK to the first one who proposed the more appropriate approach.. thanks!
CSharpNoob
hey what if i make class Casino and DrugStore also an abstract class, is there a workaround on this?
CSharpNoob
@CSharpNoob, somewhere you need to create concrete classes, but you can only pass those concrete classes in.
Albin Sunnanbo
+2  A: 

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();
        }
    }
Lie Ryan
is there where kiboard in java?
SaeedAlg
You need to add `, new()` after `: Business`
Albin Sunnanbo
@Albin Sunnanbo: Fixed. Though it just highlights the fact that I don't know C#.
Lie Ryan
+1  A: 

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

SaeedAlg
+2  A: 

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.

Groo
its basically just a Wrapper Class, (it wraps both Casino and DrugStore and expose their common methods) but as You say, I can put the common methods directly to the base class, thanks for the input..
CSharpNoob
+1  A: 

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.

supercat
+2  A: 

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;
    }
Dan Bryant