The code below produces this output fine:
This is page one.
This is page two.
But how do I change it so that the PageItem objects are instantiated dynamically from the List<string>
?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TestInstant
{
class Program
{
static void Main(string[] args)
{
List<string> pageItemsIdCodes = new List<string>() { "PageItem1", "PageItem2" };
PageItemManager pageItemManager = new PageItemManager(pageItemsIdCodes);
pageItemManager.DisplayMenu();
Console.ReadLine();
}
}
class PageItemManager
{
private Dictionary<string, BasePageItem> PageItemRecords = new Dictionary<string, BasePageItem>();
public PageItemManager(List<string> pageItemsIdCodes)
{
//manually
PageItemRecords.Add("PageItem1", new PageItem1(this));
PageItemRecords.Add("PageItem2", new PageItem2(this));
//HOW DO i DO THIS DYNAMICALLY:
//PSEUDO-CODE:
//foreach (string pageItemIdCode in pageItemsIdCodes)
//{
// Type t = Type.GetType(pageItemIdCode);开发者_StackOverflow中文版
// //ERROR: Cannot implicitly convert type 'TestInstant.PageItemManager' to 'TestInstant.BasePageItem'
// BasePageItem pageItem = Activator.CreateInstance(t, new BasePageItem[] { this });
// PageItemRecords.Add(pageItemIdCode, pageItem);
//}
//Type t = Type.GetType(pageItemIdCode);
//ERROR: Cannot implicitly convert type 'object' to 'TestInstant.BasePageItem'.
//BasePageItem pageItem = Activator.CreateInstance(t); // Change constructor
//pageItem.PageItemManager = this; // Add SetMananger call to BasePageItem
//PageItemRecords.Add(pageItemIdCode, pageItem);
}
public void DisplayMenu()
{
foreach (var pageItemRecord in PageItemRecords)
{
Console.WriteLine(pageItemRecord.Value.Title);
}
}
}
class BasePageItem
{
public string Title { get; set; }
protected PageItemManager pageItemManager;
public BasePageItem(PageItemManager pageItemManager)
{
this.pageItemManager = pageItemManager;
}
}
class PageItem1 : BasePageItem
{
public PageItem1(PageItemManager pageItemManager)
: base(pageItemManager)
{
Title = "This is page one.";
}
}
class PageItem2 : BasePageItem
{
public PageItem2(PageItemManager pageItemManager)
: base(pageItemManager)
{
Title = "This is page two.";
}
}
}
I believe you can use the Activator.CreateInstance that takes parameters for input.
foreach (string pageItemIdCode in pageItemsIdCodes)
{
Type t = Type.GetTypeFromProgID(pageItemIdCode);
Object pageItem = Activator.CreateInstance(t, new object[]{this});
PageItemRecords.Add(pageItemIdCode, pageItem);
}
Or as groo says, just cast it:
foreach (string pageItemIdCode in pageItemsIdCodes)
{
Type t = Type.GetTypeFromProgID(pageItemIdCode);
BasePageItem pageItem = (BasePageItem)Activator.CreateInstance(t, new object[]{this});
PageItemRecords.Add(pageItemIdCode, pageItem);
}
You could also do the following if you want the actually type returned:
foreach (string pageItemIdCode in pageItemsIdCodes)
{
Type t = Type.GetTypeFromProgID(pageItemIdCode);
BasePageItem pageItem = Activator.CreateInstance(t); // Change constructor
pageItem.SetMananger(this); // Add SetMananger call to BasePageItem
PageItemRecords.Add(pageItemIdCode, pageItem);
}
Here is the complete working example:
using System;
using System.Collections.Generic;
using System.Text;
namespace TestInstant
{
class Program
{
static void Main(string[] args)
{
List<string> pageItemsIdCodes = new List<string>();
pageItemsIdCodes.Add("PageItem1");
pageItemsIdCodes.Add("PageItem2");
PageItemManager pageItemManager = new PageItemManager(pageItemsIdCodes);
pageItemManager.DisplayMenu();
Console.ReadLine();
}
}
class PageItemManager
{
private Dictionary<string, BasePageItem> PageItemRecords = new Dictionary<string, BasePageItem>();
public PageItemManager(List<string> pageItemsIdCodes)
{
//manually
//PageItemRecords.Add("PageItem1", new PageItem1(this));
//PageItemRecords.Add("PageItem2", new PageItem2(this));
foreach (string pageItemIdCode in pageItemsIdCodes)
{
Type t = Type.GetType("TestInstant."+pageItemIdCode);
BasePageItem pageItem = (BasePageItem)Activator.CreateInstance(t, new Object[] { this });
PageItemRecords.Add(pageItemIdCode, pageItem);
}
}
public void DisplayMenu()
{
foreach (BasePageItem pageItemRecord in PageItemRecords.Values)
{
Console.WriteLine(pageItemRecord.Title);
}
}
}
class BasePageItem
{
private string mTitle;
public string Title { get { return mTitle; } set { mTitle = value; } }
protected PageItemManager pageItemManager;
public BasePageItem(PageItemManager pageItemManager)
{
this.pageItemManager = pageItemManager;
}
}
class PageItem1 : BasePageItem
{
public PageItem1(PageItemManager pageItemManager)
: base(pageItemManager)
{
Title = "This is page one.";
}
}
class PageItem2 : BasePageItem
{
public PageItem2(PageItemManager pageItemManager)
: base(pageItemManager)
{
Title = "This is page two.";
}
}
}
This compiles successfully. I have just tried it.
foreach(string pageItemIdCode in pageItemsIdCodes) {
Type t = Type.GetType(pageItemIdCode);
BasePageItem pageItem = (BasePageItem) Activator.CreateInstance(t, new object[] { this });
PageItemRecords.Add(pageItemIdCode, pageItem);
}
It then fails at runtime because the pageItemIdCode
values are incorrect. Changing them as follows:
List<string> pageItemsIdCodes = new List<string>() { "TestInstant.PageItem1", "TestInstant.PageItem2" };
makes the code run successfully.
You need to keep in mind that Reflection methods always return null
when they cannot find something, rather than raise an exception. If your code expects Type.GetType
to always succeed, then you need to check for nulls and raise your own exception, otherwise you will get cascading failures as the nulls are propogated through the rest of the code.
Look at the overloads for Activator.CreateInstance. You can pass in constructors in an object array for one one them.
Might I suggest Assembly.CreateInstance() You can use this function to create an instance of a specified assembly.
精彩评论