我是C#的完全新手,请原谅我,如果这看起来很奇怪。
我有一个名为vefHlutir的抽象类
namespace Klasasafn
{
public abstract class vefHlutur
{
public abstract List<String> columnNames();
public abstract List<String> toStringList();
}
}
//Here is an object that inherits from this abstract class:
namespace Klasasafn
{
[Table(Name="Users")]
public class User: vefHlutur
{
public override List<String> columnNames()
{
List<String> p = new List<String>();
p.Add("Nafn");
p.Add("Email");
p.Add("Lýsing");
return p;
}
public override List<String> toStringList()
{
List<String> p = new List<String>();
p.Add(name);
p.Add(email);
p.Add(descr);
return p;
}
... more stuff here
}
}
//And here is the code I'm trying to run, Item, User and Category all inherit from vefHlutir:
List<Klasasafn.Item> hlutir;
List<Klasasafn.User> notendur;
List<Klasasafn.Category> flokkar;
void Page_Init(object sender, EventArgs e)
{
hlutir = Fac.getItemList();
notendur = Fac.getUserList();
flokkar = Fac.getCategoryList();
prenta(notendur, Table1);
}
protected void Page_Load(object sender, EventArgs e)
{
}
protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
{
}
protected void Button1_Click(object sender, EventArgs e)
{
if (DropDownList1.SelectedIndex == 0)
{
prenta(notendur, Table1);
}
else if (DropDownList1.SelectedIndex == 1)
{
prenta(hlutir, Table1);
}
else
prenta(flokkar, Table1);
}
private void prenta(List<vefHlutur> foo, Table f)
{
List<String> columnNames = foo[0].columnNames();
TableRow tRow1 = new TableRow();
f.Rows.Add(tRow1);
foreach (String i in columnNames)
{
TableCell columnNameCell = new TableCell();
tRow1.Cells.Add(columnNameCell);
columnNameCell.Controls.Add(new LiteralControl(i));
}
foreach (vefHlutur j in foo)
{
TableRow tRow = new TableRow();
f.Rows.Add(tRow);
List<String> töfluHlutir = j.toStringList();
foreach (String k in töfluHlutir)
{
TableCell tCell1 = new TableCell();
tRow.Cells.Add(tCell1);
tCell1.Controls.Add(new LiteralControl(k));
}
}
}
namespace Klasasafn
{
public abstract class vefHlutur
{
public abstract List<String> columnNames();
public abstract List<String> toStringList();
}
}
我的问题是我无法使用prenta方法。
我总是遇到这些错误:
错误1'Forsíða.prenta(System.Collections.Generic.List,System.Web.UI.WebControls.Table)'的最佳重载方法匹配有一些无效的参数
错误2参数'1':无法从'System.Collections.Generic.List'转换为'System.Collections.Generic.List
我该如何解决这个问题?
答案 0 :(得分:8)
问题是在C#中,当为List<ChildClass>
键入方法时,无法使用类型List<ParentClass>
。这种类型的转换称为协方差,它在C#中直到4.0才可用,然后仅在接口和事件上可用。
你可以做的是使方法通用并添加约束。
private void prenta<T>(List<T> foo, Table f)
where T : vefHlutur
{
...
}
此代码正在做的是说prenta将接受List<T>
作为任何T为或来自vefHlutur类型的派生的情况的第一个参数。它还允许您将类型T视为关于调用方法,属性等的类型vefHlutur ...这应该允许您的方案工作。
答案 1 :(得分:0)
有一种方法可以进行演员表演。有点不安全的代码!不要害怕这篇文章。它主要是测试代码,以显示它的工作原理。所有工作都在这里进行:
static unsafe List<A> CastBasAIL(List<B> bIn) {
DynamicMethod dynamicMethod = new DynamicMethod("foo1", typeof(List<A>),
new[] { typeof(List<B>) }, typeof(void));
ILGenerator il = dynamicMethod.GetILGenerator();
il.Emit(OpCodes.Ldarg_0); // copy first argument to stack
il.Emit(OpCodes.Ret); // return the item on the stack
CCastDelegate HopeThisWorks = (CCastDelegate)dynamicMethod.CreateDelegate(
typeof(CCastDelegate));
return HopeThisWorks(bIn);
}
只要您尝试投射的内容具有与您投射到的内容相同的实例字段布局(继承情况正常),此解决方案就可以正常工作。请注意,有些内容会导致类型不匹配错误:即,如果List尝试在协变情况下创建基类型。只需在完成此操作后进行测试。
我向纯粹主义者道歉,但我是一名康复的c / c ++ vb / aseembly程序员!
namespace Covariant {
class A {
public virtual string Name() { return "A"; }
}
class B : A {
public override string Name() { return "B"; }
}
delegate List<A> CCastDelegate(List<B> b); // be used in the cast
class Program {
static unsafe List<A> CastBasAIL(List<B> bIn) {
DynamicMethod dynamicMethod = new DynamicMethod("foo1", typeof(List<A>), new[] { typeof(List<B>) }, typeof(void));
ILGenerator il = dynamicMethod.GetILGenerator();
il.Emit(OpCodes.Ldarg_0); // copy first argument to stack
il.Emit(OpCodes.Ret); // return the item on the stack
CCastDelegate HopeThisWorks = (CCastDelegate)dynamicMethod.CreateDelegate(typeof(CCastDelegate));
return HopeThisWorks(bIn);
}
static void Main(string[] args) {
// make a list<B>
List<B> b = new List<B>();
b.Add(new B());
b.Add(new B());
// set list<A> = the list b using the covariant work around
List<A> a = CastBasAIL(b);
// at this point the debugger is miffed with a, but code exectuing methods of a work just fine.
// It may be that the debugger simply checks that type of the generic argument matches the
// signature of the type, or it may be that something is really screwed up. Nothing ever crashes.
// prove the cast really worked
TestA(a);
return;
}
static void TestA(List<A> a) {
Console.WriteLine("Input type: {0}", typeof(List<A>).ToString());
Console.WriteLine("Passed in type: {0}\n", a.GetType().ToString());
// Prove that A is B
Console.WriteLine("Count = {0}", a.Count);
Console.WriteLine("Item.Name = {0}", a[0].Name());
// see if more complicated methods of List<A> still work
int i = a.FindIndex(delegate(A item) { return item.Name() == "A"; });
Console.WriteLine("Index of first A in List<A> = {0}", i);
i = a.FindIndex(delegate(A item) { return item.Name() == "B"; });
Console.WriteLine("Index of first B in List<A> = {0}\n", i);
// can we convert a to an array still?
Console.WriteLine("Iterate through a, after converting a to an array");
foreach (var x in a.ToArray())
Console.WriteLine("{0}", x.Name());
}
}
}