Dyanamically referring to an object instance

R

RSH

Hi,

I have a situation where I have multiple objects created from concrete
classes:

// Concrete implementations of the Abstract class ApprovalChain
MarketingApprovalChain MktgAppChain = new MarketingApprovalChain();
AccountingApprovalChain AcctAppChain = new AccountingApprovalChain();

I also have a Department enum
public enum Department
{
Acct,Mktg
}

Armed with that information I need to pass those objects to another class
dynamically. (Im trying to avoid hardcoding the logic is a case conditional:

public class Purchase
{
public Purchase(ApprovalChain appChain)
{
...
}

}


back to the original method:
private MarketingApprovalChain MktgAppChain = new MarketingApprovalChain();
private AccountingApprovalChain AcctAppChain = new
AccountingApprovalChain();

public void PurchaseRequisition(Department dept)
{
Purchase purchase = new Purchase();<----- is there a way here to use the
string value of the enum to dynamically make reference to the appropriate
ApprovalChain to pass to the Purchase Class Constructor?
}

PsuedoCode: Purchase purchase = new Purchase(dept.ToString() +
"ApprovalChain");

Thanks alot!

Ron
 
C

cfps.Christian

Took me a minute to figure out what you wanted to do.

You're looking for the Activator.CreateInstance method.

What I would do is:

ApprovalChain appChain;
appChain = (ApprovalChain)Activator.CreateInstance([fully qualified
name] + dept.ToString() + "ApprovalChain")
Purchase purchase = new Purchase(appChain);

I'm not really up on my CreateInstance code but thats definitely what
you're looking for. The string that you pass in has to be the fully
qualified name of the type you are defining.
 
R

RSH

Almost....

The only problem is that the objects already have been created and they
contain state that needs to be persisted which is handled by the class that
contains the method Im illustrating here. I need to dynamically construct a
reference to the appropriate object (based on the deparment enum passed to
the method) and then pass the "live" object to the Purchase object. Right
now I am using a case conditionional:

public void PurchaseRequest(int id, double amount, string description,
eGroup group)

{

Purchase purchase;

switch (group)

{

case eGroup.Marketing:

this.

purchase = new Purchase(id, amount, description, group,
marketingapprovalchain, marketingbudget);

break;

case eGroup.Accounting:

purchase = new Purchase(id, amount, description, group,
accountingapprovalchain, accountingbudget);

break;

}

}

}



But since I dont know the number of departments the system will ultimately
contain, I dont want to hardcode the references in a conditional.



Thanks!

Ron
 
M

Mattias Sjögren

PsuedoCode: Purchase purchase = new Purchase(dept.ToString() +
"ApprovalChain");


How about a simple mapping table?

Dictionary<Department, ApprovalChain> map = new Dictionary<Department,
ApprovalChain>();
map.Add(Department.Acct, AcctAppChain);
map.Add(Department.Mktg, MktgAppChain);

....

Purchase purchase = new Purchase(map[dept]);


Mattias
 
P

Peter Duniho

[...]
But since I dont know the number of departments the system will ultimately
contain, I dont want to hardcode the references in a conditional.

It's difficult for me to be sure I completely understand the question.
I don't find the description very organized. But, that said...

It seems to me that what you've got are already-existing instances of
ApprovalChain-derived classes that are somehow related to your
instantiation of the Purchase class. It appears you may also have a
class named "Budget" that also has derived versions you're using.

Given that, you may want to consider just storing those instances in a
Dictionary<T>, so that you can easily look them up according to their
enum value. For example:

enum Department
{
Acct, Mktg
}

struct DepartmentObjects
{
public readonly ApprovalChain ApprovalChain;
public readonly Budget Budget;

public DepartmentObjects(ApprovalChain ApprovalChain, Budget Budget)
{
this.ApprovalChain = ApprovalChain;
this.Budget = Budget;
}
}

static Dictionary<Department, DepartmentObjects> dictDepartments;

// run once somewhere (e.g. static constructor for whatever class
// contains the "dictDepartments" object)
foreach (Department dept in Department.GetValues())
{
switch (dept)
{
case Acct:
dictDepartments.Add(dept, new DepartmentObjects(new
AccountingApprovalChain(), new AccountingBudget()));
break;
case Mktg:
dictDepartments.Add(dept, new DepartmentObjects(new
MarketingApprovalChain(), new MarketingBudget()));
break;
}
}


// then wherever you need to match the enum to an instance, something
// like this:

Department dept = // initialized however...;

ApprovalChain approval = dictDepartments[dept].ApprovalChain;

// Or you could do this:
DepartmentObject do = dictDepartments[dept];
Purchase purchase = new Purchase(id, amount, description, dept,
do.ApprovalChain, do.Budget);

etc.

Note that at some point you do need to hardcode the relationship
between your enum and the class each value represents. Depending on
the actual names you've used for things it certainly is possible to use
reflection to even automate that, but it seems to me it wouldn't really
buy you much. It's not like you can just go adding new ApprovalChain
and Budget objects without visiting the code that uses those objects
and verifying you've done everything right anyway (or at least you
ought to be).

Pete
 
R

RSH

Peter,

Thanks! Good stuff...that worked perfectly!

I agree that at some point I need to hardcode the names, but I wanted to do
it in one place only. Your solution will provide me that.

thanks!
Ron


Peter Duniho said:
[...]
But since I dont know the number of departments the system will
ultimately
contain, I dont want to hardcode the references in a conditional.

It's difficult for me to be sure I completely understand the question. I
don't find the description very organized. But, that said...

It seems to me that what you've got are already-existing instances of
ApprovalChain-derived classes that are somehow related to your
instantiation of the Purchase class. It appears you may also have a class
named "Budget" that also has derived versions you're using.

Given that, you may want to consider just storing those instances in a
Dictionary<T>, so that you can easily look them up according to their enum
value. For example:

enum Department
{
Acct, Mktg
}

struct DepartmentObjects
{
public readonly ApprovalChain ApprovalChain;
public readonly Budget Budget;

public DepartmentObjects(ApprovalChain ApprovalChain, Budget
Budget)
{
this.ApprovalChain = ApprovalChain;
this.Budget = Budget;
}
}

static Dictionary<Department, DepartmentObjects> dictDepartments;

// run once somewhere (e.g. static constructor for whatever class
// contains the "dictDepartments" object)
foreach (Department dept in Department.GetValues())
{
switch (dept)
{
case Acct:
dictDepartments.Add(dept, new DepartmentObjects(new
AccountingApprovalChain(), new AccountingBudget()));
break;
case Mktg:
dictDepartments.Add(dept, new DepartmentObjects(new
MarketingApprovalChain(), new MarketingBudget()));
break;
}
}


// then wherever you need to match the enum to an instance, something
// like this:

Department dept = // initialized however...;

ApprovalChain approval = dictDepartments[dept].ApprovalChain;

// Or you could do this:
DepartmentObject do = dictDepartments[dept];
Purchase purchase = new Purchase(id, amount, description, dept,
do.ApprovalChain, do.Budget);

etc.

Note that at some point you do need to hardcode the relationship between
your enum and the class each value represents. Depending on the actual
names you've used for things it certainly is possible to use reflection to
even automate that, but it seems to me it wouldn't really buy you much.
It's not like you can just go adding new ApprovalChain and Budget objects
without visiting the code that uses those objects and verifying you've
done everything right anyway (or at least you ought to be).

Pete
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top