为什么我会为以下代码获取类型转换编译错误?
我的项目中有很多派生Def / View类的实例。所有这些都有一些代码库,比如持久性,检索等。我想通过使用泛型编写一个帮助器类,我可以实现这个公共代码库的可维护性。
但是,在将视图分配给def的行上,DoSomeStuff方法中出现“类型转换”编译错误。我已经注意为所有基类和派生类编写隐式转换转换。
注意Def&故意查看类不是从某些常见类派生的。另外,我总是希望仅从View转换为Def,而不是反过来,因此只有我的View类具有在它们上定义的隐式转换。
我确实试着跟随Eric Lipert关于协方差和反演的讨论,但是随着他的例子的进展,我的脑子里充满了混乱。非常感谢任何有关此问题的帮助。
public class BaseDef
{
public int Id { get; set; }
}
public class DerivedDef : BaseDef
{
public string Name { get; set; }
public DerivedDef()
: base()
{
}
public DerivedDef(BaseDef bd)
{
this.Id = bd.Id;
}
}
public class BaseView
{
public int Id { get; set; }
public BaseView()
{
}
public BaseView(BaseDef bd)
{
Id = bd.Id;
}
public BaseDef ToBaseDef()
{
return new BaseDef { Id = this.Id };
}
public static implicit operator BaseView(BaseDef bd)
{
return new BaseView(bd);
}
public static implicit operator BaseDef(BaseView bv)
{
return bv.ToBaseDef();
}
}
public class DerivedView : BaseView
{
public string Name { get; set; }
public DerivedView()
: base()
{
}
public DerivedView(DerivedDef dd)
: base(dd)
{
Name = this.Name;
}
public DerivedDef ToDerivedDef()
{
return new DerivedDef(this)
{
Name = this.Name,
};
}
}
public class SomeHelper<Tdef, Tview>
where Tdef : BaseDef
where Tview : BaseView
{
public void DoSomeStuff(Tview vm)
{
Tdef df = vm; // this line give a compile error 'Cannot convert type 'Tview' to 'Tdef'
// work with df from here on
}
}
答案 0 :(得分:2)
无法保证 转换为Tdef
。肯定会转换为BaseDef
,编译器将使用该转换:
BaseDef df = vm; // This is fine
......但那不是一回事。
在这种情况下,转换实际上会返回BaseDef
- 没有转化运算符从DerivedView
到DerivedDef
...方法(ToDerivedDef
),但代码中没有任何内容可以调用它。即使在这种特殊情况下存在转换,编译器也不能保证它存在。
您可以使用:
Tdef df = (Tdef) (BaseDef) vm;
...将执行用户定义的转换为BaseDef
,然后执行正常转换为Tdef
- 在您的情况下执行时会失败,但如果转换调用则可能有效一个合适的虚拟方法。但是在编译时它不能保证。
答案 1 :(得分:0)
我真的无法使用Jon的方法,因为我有分层约束。 def模型在DB层中定义,而在UI层中定义视图模型。
然而,从Jon的评论中汲取灵感,我如何解决手头的问题是在所有视图模型上添加隐式转换,并在辅助类上公开处理转换为&amp;的两个属性。来回。这是最终代码的外观......
public class BaseDef
{
public int Id { get; set; }
public override string ToString()
{
return Id.ToString();
}
}
public class BaseView
{
public int Id { get; set; }
public BaseView()
{
}
public BaseView(BaseDef bd)
{
Id = bd.Id;
}
public BaseDef ToBaseDef()
{
return new BaseDef { Id = this.Id };
}
public static implicit operator BaseView(BaseDef bd)
{
return new BaseView(bd);
}
public static implicit operator BaseDef(BaseView bv)
{
return bv.ToBaseDef();
}
}
public class DerivedDef : BaseDef
{
public string Name { get; set; }
public DerivedDef()
: base()
{
}
public DerivedDef(BaseDef bd)
{
this.Id = bd.Id;
}
}
public class DerivedView : BaseView
{
public string Name { get; set; }
public DerivedView()
: base()
{
}
public DerivedView(DerivedDef dd)
: base(dd)
{
Name = this.Name;
}
public DerivedDef ToDerivedDef()
{
return new DerivedDef((BaseView)this)
{
Name = this.Name,
};
}
public static implicit operator DerivedView(DerivedDef dd)
{
return new DerivedView(dd);
}
public static implicit operator DerivedDef(DerivedView dv)
{
return dv.ToDerivedDef();
}
}
public class SomeHelper<Tdef, Tview>
where Tdef : BaseDef
where Tview : BaseView
{
public Func<Tview, Tdef> ConvertToDef { get; set; }
public Func<Tdef, Tview> ConvertToView { get; set; }
public Tdef Convert(Tview vm)
{
if (ConvertToDef == null)
{
throw new ArgumentNullException("ConvertToDef uninitialized");
}
return ConvertToDef(vm);
}
public Tview Convert(Tdef dm)
{
if (ConvertToView == null)
{
throw new ArgumentNullException("ConvertToView uninitialized");
}
return ConvertToView(dm);
}
}
消费代码看起来像这样......
private static void TestCastWithGenerics()
{
BaseDef bd = new BaseDef()
{
Id = 1
};
DerivedView dv = new DerivedView()
{
Id = 1,
Name = "DV",
};
var aClassD = new SomeHelper<DerivedDef, DerivedView>();
aClassD.ConvertToDef = dv1 => dv1; // Behind scenes the implicit cast is being invoked...
DerivedDef dd = aClassD.Convert(dv);
var aClassB = new SomeHelper<BaseDef, BaseView>();
aClassB.ConvertToView = bd1 => bd1; // Behind scenes the implicit cast is being invoked...
BaseView bv = aClassB.Convert(bd);
Console.WriteLine(dd);
Console.WriteLine(bv);
}