用具体类型覆盖的抽象方法

时间:2015-10-27 13:46:49

标签: c# generics inheritance design-patterns abstract-class

也许这是一个愚蠢的问题。但是,我不明白我错过了什么。

给出以下类定义

public abstract class AbstractBaseClass
{
    public abstract void Create(AnotherAbstractClass param1);
}

定义了AnotherAbstractClass

public abstract class AnotherAbstractClass
{
}

具体实施

public class AnotherConcreteImplementation : AnotherAbstractClass
{
}

我希望能够覆盖Create方法以使用具体类型:

public class ConcreteImplementation : AbstractBaseClass
{
    public override void Create(AnotherConcreteImplementation param1) <-- There is no suitable method for override
    {
        // param1 is an instance of the concrete implementation
    }

    public override void Create(AnotherAbstractClass param1) <-- this is working but I'll have to cast on each implementation
    {
        // param1 is an instance of the abstract class and needs a cast
    }
}

这根本不可能,还是有某些方法我不知道?也许使用泛型?

编辑#1 (添加了更多上下文)

我正在尝试实现/强制执行在具体实现中只有一个参数有效。 可以把它想象成一个数据库层。 Create方法将在数据库中创建一个新条目。由于每个表都有不同的值,create-parameter也有。 内部气味(在我看来)可以通过AnotherAbstractClass的任何具体实现来调用。

public class AddressTable : AbstractBaseClass
{
    public override void Create(AnotherAbstractClass param1)
    {
        // cast to concrete instance
        var casted = (ConcreteAddressCreate)param1;
    }
}

public class CityTable : AbstractBaseClass
{
    public override void Create(AnotherAbstractClass param1)
    {
        // cast to concrete instance
        var casted = (ConcreteCityCreate)param1;
    }
}

拥有AddressTable的实例我可以致电

addressIntance.Create(new ConcreteAddressCreate()); // would be okay
另一方面,我可以称之为

addressIntance.Create(new ConcreteCityCreate()); // would be okay but will fail at runtime with InvalidCastException

编辑#2 (其他信息)

稍后还可以使用更抽象的方法扩展AbstractBaseClass类。 所以,对我来说,更有可能使用泛型方法而不是具体的类实现,每个方法都要实现200个通用参数。

3 个答案:

答案 0 :(得分:2)

它违反了Liskov替换原则,所以你完全没有理由这样做。也就是说,你不能只是&#34;有&#34;这样的协方差是免费的:

AbstractBaseClass bcl = new ConcreteImplementation();
bcl.Create(new DifferentImplementationWithoutSecondAbstract());

合同AbstractBaseClass定义make Create必须与传入的AbstractBaseClass任何实现一起使用 - 如果你对你可以传递的内容给出约束。违反了它定义的合同。

就像你假设的那样 - 你可以使用泛型:

// notice the recursive definition, we require the generic parameter
// to be a generic parameter of itself - allowing AbstractBaseClass
// to not be aware of its subclasses like in the other answers.
public abstract class AbstractBaseClass<T> where T : AbstractBaseClass<T>
{
    public abstract void Create(T param1);
}

public class Concrete : AbstractBaseClass<Concrete>
{
    public override void Create(Concrete param1)
    {
        Console.WriteLine("Hello!");
    }
}

答案 1 :(得分:2)

是的,你可以使用泛型来做到这一点:

public abstract class AbstractBaseClass<T>
    where T : AnotherAbstractClass
{
    public abstract void Create(T param1);
}

public class ConcreteImplementation : AbstractBaseClass<AnotherConcreteImplementation>
{
    public override void Create(AnotherConcreteImplementation param1)
    {
    }
}

答案 2 :(得分:0)

泛型确实是这样做的方式。

    $.ajax({
          url: resource_str,
          type: "GET",
          async:   true,
        },
          success: function(data) {
        var file = new Blob([data], {type: 'text/plain'});
                        var fileURL = URL.createObjectURL(file);
                        window.open(fileURL);
                        var a = document.createElement("a");
                        a.href = fileURL;
                        a.download = "Testing.pdf";
                        document.body.appendChild(a);
                        a.click();
                        $(window).on('focus', function(e) {
                          $('a').remove();
                        });
        },fails: function (data){
          console.log('Error');
        }
    })

然后你可以这样做:

public abstract class AbstractBaseClass<TDerivedClass> where TDerivedClass : AnotherAbstractClass
{
    public abstract void Create(TDerivedClass param1);
}