Fam*_*erd 4 .net c# generics covariance .net-3.5
我编写了ASP.NET页面来管理表单.它们基于以下基类.
public abstract class FormPageBase<TInterface, TModel> : Page, IKeywordProvider
where TModel:ActiveRecordBase<MasterForm>, TInterface, new()
where TInterface:IMasterForm
{
public TInterface FormData { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
一个示例SubClass在这里:
public partial class PersonalDataFormPage : FormPageBase<IPersonalDataForm, PersonalDataForm>, IHasFormData<IPersonalDataForm>, IHasContact
{
}
Run Code Online (Sandbox Code Playgroud)
下面我在页面上有一个usercontrol,我想从页面"使用""FormData",以便它可以读/写它.
然后,我有一个更"通用"的用户控件,我想在我所有的表单子类的基接口上操作... IMasterForm
但是当usercontrol尝试强制转换Page.FormData时(尝试将页面强制转换为IHasFormData<IMasterForm>
它)告诉我该页面IHasFormData<IFormSubclass>
即使我对IFormSubclass有一个约束,它说它也是IMasterForm
无论如何,我可以从通用子类转换为通用超类,还是这个"协方差"和C#4.0的东西?
public abstract class FormControlBase<T> : UserControl, IKeywordProvider
where T:IMasterForm
{
protected T FormData { get; set; }
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
//This cast is failing when my common control's T does not exactly match
// the T of the Page.. even though the common controls TInterface is a base interface to the
//pages TInterface
FormData = ((IHasFormData<T>) Page).FormData;
if (!IsPostBack)
{
PopulateBaseListData();
BindDataToControls();
}
}
protected abstract void PopulateBaseListData();
protected abstract void BindDataToControls();
public abstract void SaveControlsToData();
#region IKeywordProvider
public List<IKeyword> GetKeywords(string categoryName)
{
if(!(Page is IKeywordProvider ))
throw new InvalidOperationException("Page is not IKeywordProvider");
return ((IKeywordProvider) Page).GetKeywords(categoryName);
}
#endregion
}
Run Code Online (Sandbox Code Playgroud)
Eri*_*ert 14
让我先看看能否更简洁地重述这个复杂的问题.你有一个通用的界面IHasFormData<T>
.你有一个已知的实现对象IHasFormData<IFormSubclass>
.你希望将其转换为IHasFormData<IMasterForm>
.您知道有一个从IFormSubclass到IMasterForm的引用转换.这失败了.
是?
如果这是对问题的正确陈述,那么是的,这是界面协方差的问题.C#3不支持接口协方差.如果你能向编译器证明协方差是安全的,那么 C#4将会出现.
让我简要介绍一下为什么这可能不安全.假设您有Apple,Orange和Fruit类,具有明显的子类关系.你有一个IList<Apple>
你想要投射的IList<Fruit>
.这种协变转换在C#4中是不合法的,并且不合法,因为它不安全.假设我们允许它.然后你可以这样做:
IList<Apple> apples = new List<Apple>();
IList<Fruit> fruits = apples;
fruits.Add(new Orange());
// We just put an orange into a list of apples!
// And now the runtime crashes.
Run Code Online (Sandbox Code Playgroud)
请注意,问题是List<T>
暴露了一个以T为参数的方法.为了让编译器允许在您的接口上进行协变转换IHasFormData<T>
,您必须向编译器证明IHasFormData<T>
没有公开任何以T为参数的内容.你会通过声明界面来做到这一点,这是IHasFormData<out T>
一个助记符,意思是"T只出现在输出位置".然后,编译器将验证您的声明是否正确,并开始允许协变转换.
有关C#4中此功能的更多信息,请参阅我的功能设计说明存档:
http://blogs.msdn.com/ericlippert/archive/tags/Covariance+and+Contravariance/default.aspx
归档时间: |
|
查看次数: |
701 次 |
最近记录: |