我有以下情况:
class MyControl<T> : UserControl where T:TClass
{
public T Field {}
public event EventHandler<MyEventArgs<T>> MyEvent;
}
class DerControl1 : MyControl<ClassA> {}
class DerControl2 : MyControl<ClassB> {}
我应该如何实现继承以获得DerControl1的基类,DerControl2可以访问MyControl的接口?
SomeBaseClass control = condition ? DerControl1 :DerControl2;
control.Field = null;
control.Enabled=false;
SomeBaseClass应该是什么类?
答案 0 :(得分:2)
定义另一个非通用接口IMyControl
并明确实现它:
public interface IMyControl
{
public TClass Field { get; set; }
public bool Enabled { get; set; }
}
class MyControl<T> : UserControl, IMyControl where T:TClass
{
public T Field { get; set; }
TClass IMyControl.Field
{
get { return this.Field; }
set { this.Field = (T)value; }
}
public event EventHandler<MyEventArgs<T>> MyEvent;
}
现在,您可以将派生控件转换为IMyControl
,并将Field
属性作为类型TClass
进行访问。尝试返回其他任何内容违反co/contravariance(您可以返回object
但在这种情况下最好返回TClass
,因为类型约束已经存在)
答案 1 :(得分:1)
您可以使用UserControl
访问Enabled
字段,但没有定义Field
的常见类型。您不能将Field
放在一个通用的非泛型接口中,因为它的类型是通用的。
从C#4.0开始,您可以使用dynamic
来实现这样的目标:
dynamic control = condition ? DerControl1 :DerControl2;
control.Field = null;
control.Enabled=false;
这可能会稍慢,但它会编译并执行您想要的操作。
答案 2 :(得分:0)
用例不清楚。 如果这段代码:
control.Field = null;
control.Enabled=false;
不会被放入泛型方法(或泛型方法),而不是根本不需要泛型:
class MyControl : UserControl where T:TClass
{
public object Field {}
public event EventHandler<MyEventArgs> MyEvent;
}
否则,此代码将正常工作。
答案 3 :(得分:0)
使用您自己的问题,您不能只使用界面吗?
public interface IMyControl<T> where T:class
{
T Field { get; set;}
event EventHandler<MyEventArgs<T>> MyEvent;
}
public class MyControl<T> : UserControl, IMyControl<T> where T:class
{
public T Field { get; set;}
public event EventHandler<MyEventArgs<T>> MyEvent;
}
然后使用:
// (which equates to IMyControl control = ...)
var control = condition ? new MyControl<ClassA>() : new MyControl<ClassB>();
control.Field = null;
control.Enabled = false;
这可以节省您为要使用的每个Type参数设置多个类,从而鼓励代码重用并遵循多态(OOP)。
希望有帮助!
修改强>
好的 - 所以亚历克斯是对的,我不应该对那个人开火!经过一番调查后,这似乎比我想象的要困难得多!所以我开始怀疑你所问的是不是正确的方法。现在,无论是否是你想要的那种答案,我都不知道,但这里是你的思考。
基本上,不要使用泛型。在这种情况下,它会让生活变得非常困难!相反,隐藏在接口后面。下面的代码实现了与您上面尝试的相同,但除了您现在将字段绑定到“具体”接口。但实际上,你想要这个 - 你应该知道已知的行为和模式,否则,在我看来,你不知道你的系统应该做什么,因此你的要求有问题。无论如何,这是一些代码!
public interface IMyClass
{
int I { get; set; }
string S { get; set; }
}
public interface IMyControl
{
IMyClass Field { get; set; }
event EventHandler<EventArgs> MyEvent;
}
public class MyControl : UserControl, IMyControl
{
public MyControl(IMyClass field)
{
this.Field = field;
}
public IMyClass Field { get; set; }
public event EventHandler<EventArgs> MyEvent;
}
public class MyClass1 : IMyClass
{
public int I { get; set; }
public string S { get; set; }
public override string ToString()
{
return "I am a MyClass1!!!";
}
}
public class MyClass2 : IMyClass
{
public int I { get; set; }
public string S { get; set; }
public override string ToString()
{
return "I am a MyClass2!!!";
}
}
var control = someCondition ? new MyControl(new MyClass1()) : new MyControl(new MyClass2());