简体   繁体   English

泛型类继承问题

[英]Generic class Inheritance issue

I have the following situation: 我有以下情况:

class MyControl<T> : UserControl where T:TClass
{
    public T Field {}
    public event EventHandler<MyEventArgs<T>> MyEvent;
}
class DerControl1 : MyControl<ClassA> {}
class DerControl2 : MyControl<ClassB> {}

How I should implement inheritance to have a base class for DerControl1, DerControl2 to have access to interface of MyControl? 我应该如何实现继承以使DerControl1具有基类,DerControl2可以访问MyControl的接口?

SomeBaseClass control = condition ? DerControl1 :DerControl2;
control.Field = null;
control.Enabled=false;

What class should SomeBaseClass be? SomeBaseClass应该是什么类?

Define another, non-generic interface IMyControl and implement it explicitly: 定义另一个非通用接口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;
}

You can now cast your derived controls to IMyControl and access the Field property as a type TClass . 您现在可以将派生控件转换为IMyControl ,并将Field属性作为类型TClass Trying to return as anything else violates co/contravariance (you can return an object but it is preferable in this case to return a TClass since the type constraint already exists) 试图返回其他任何违反co / contravariance的东西(你可以返回一个object但在这种情况下最好返回一个TClass因为类型约束已经存在)

You can use UserControl to access the Enabled field, but there is no common type that defines Field . 您可以使用UserControl访问Enabled字段,但没有定义Field常用类型。 You cannot put Field in a common non-generic interface, because its type is generic. 您不能将Field放在一个通用的非泛型接口中,因为它的类型是通用的。

Starting with C# 4.0, you can use dynamic for things like that: 从C#4.0开始,您可以使用dynamic类似的东西:

dynamic control = condition ? DerControl1 :DerControl2;
control.Field = null;
control.Enabled=false;

This may be slightly slower, but it will compile and do what you want. 这可能会稍慢,但它会编译并执行您想要的操作。

The use case is unclear. 用例不清楚。 If this code: 如果这段代码:

control.Field = null;
control.Enabled=false;

won't be placed into a generic method (or into a method of a generic type), than you don't need generic at all: 将不会放入泛型方法(或泛型方法),而不是根本不需要泛型:

class MyControl : UserControl where T:TClass
{
    public object Field {}
    public event EventHandler<MyEventArgs> MyEvent;
}

Otherwise, this code will work just fine. 否则,此代码将正常工作。

Using your own question, couldn't you just use an interface? 使用您自己的问题,您不能只使用一个界面吗?

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;       
}

And then to use : 然后使用:

// (which equates to IMyControl control = ...)
var control = condition ? new MyControl<ClassA>() : new MyControl<ClassB>();
control.Field = null;
control.Enabled = false;

This saves you having multiple classes for each Type parameter you want to use and therefore encourages code reuse and follows polymorphism (OOP). 这样可以节省您希望使用的每个Type参数的多个类,从而鼓励代码重用并遵循多态(OOP)。

Hope that is helpful! 希望有所帮助!

EDIT 编辑

OK - so Alex was right and I shouldn't have fired from the hip on that one! 好的 - 所以亚历克斯是对的,我不应该对那个人开火! After a bit of investigation this seems to be a lot harder than I thought! 经过一番调查后,这似乎比我想象的要困难得多! So I began to wonder if what you're asking is the right way to go. 所以我开始怀疑你所问的是不是正确的方法。 Now, whether it is the sort of answer you want or not, I don't know, but here it is for you to ponder. 现在,无论是否是你想要的那种答案,我都不知道,但这里是你思考的问题。

Basically, donn't use generics. 基本上,不要使用泛型。 It makes life really really difficult in this scenario! 在这种情况下,它会让生活变得非常困难! Instead, hide behind interfaces. 相反,隐藏在接口后面。 The code below achieves the same as you're trying to above, but with the exception that you now have field tied to a 'concrete' interface. 下面的代码实现了与您上面尝试的相同,但除了您现在将字段绑定到“具体”接口。 But realistically, you want this - you should have known behaviours and patterns, otherwise, to my mind, you don't know what your system should be doing and therefore there's something wrong with your requirements. 但实际上,你想要这个 - 你应该知道已知的行为和模式,否则,在我看来,你不知道你的系统应该做什么,因此你的要求有问题。 Anyway, surmon over, here's some code! 不管怎么说,这里有一些代码!

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());

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM