c#中的继承问题

本文关键字:问题 继承 | 更新日期: 2023-09-27 18:06:06

我正在重构一些代码,希望在继承链中更高一点的类对它们的参数更严格一点。由于我不确定我的解释是否正确,以下是我得到的:

public interface ISvdPredictor
{
    List<string> Users { get; set; }
    List<string> Artists { get; set; }
    float PredictRating(ISvdModel model, string user, string artist);
    float PredictRating(ISvdModel model, int userIndex, int artistIndex);
}

ISvdPredictor使用ISvdModel:

public interface ISvdModel
{
    float[,] UserFeatures { get; set; }
    float[,] ArtistFeatures { get; set; }
}

现在我想实现另一个变体:

public interface IBiasSvdPredictor : ISvdPredictor
{
    float PredictRating(IBiasSvdModel model, string user, string artist);
    float PredictRating(IBiasSvdModel model, int userIndex, int artistIndex);
}

使用由ISvdModel衍生而来的IBiasSvdModel:

public interface IBiasSvdModel : ISvdModel
{
    float GlobalAverage { get; set; }
    float[] UserBias { get; set; }
    float[] ArtistBias { get; set; }
}

IBiasSvdPredictor不能与ISvdModel一起工作。

问题是,当我实现IBiasSvdPredictor时,我必须实现2对预测方法。一个来自ISvdPredictor,另一个来自IBiasSvdPredictor。我需要做些什么才能实现那些从IBiasSvdPredictor ?

我也尝试过泛型,但不能使用where指令将BiasSvdPredictorPredictRating限制为IBiasSvdModel。我可能做错了,所以任何建议可能会有所帮助。我想你明白我的意思了。

编辑:如果有人需要更多的背景,请参阅https://github.com/gligoran/RecommendationSystem。我正在为我的学士学位论文写这段代码。

c#中的继承问题

可以使用泛型和约束。

public interface ISvdModel
{
    float[,] UserFeatures { get; set; }
    float[,] ArtistFeatures { get; set; }
}
public interface IBiasSvdModel : ISvdModel
{
    float GlobalAverage { get; set; }
    float[] UserBias { get; set; }
    float[] ArtistBias { get; set; }
}
public interface ISvdPredictor<in TSvdModel>
    where TSvdModel : ISvdModel // Require that TSvdModel implements ISvdModel
{
    List<string> Users { get; set; }
    List<string> Artists { get; set; }
    float PredictRating(TSvdModel model, string user, string artist);
    float PredictRating(TSvdModel model, int userIndex, int artistIndex);
}
// I would actually avoid declaring this interface. Rather, see comment on the class.
public interface IBiasSvdPredictor : ISvdPredictor<IBiasSvdModel> { }
class BiasSvdPredictor : IBiasSvdPredictor // Preferred : ISvdPredictor<IBiasSvdModel>
{
    // ...
    public float PredictRating(IBiasSvdModel model, string user, string artist) { }
    public float PredictRating(IBiasSvdModel model, int userIndex, int artistIndex) { }
}

interface应该有一个方法PredictRating。我不会让两个接口实现相同的方法。混乱。

创建实现interfaceabstract类。使PredictRating成为virtual方法,以便继承者可以在他们认为合适的时候重写。你甚至可以在抽象类上做一个默认实现。

一个接口,一个抽象类。N个实现他们认为合适的predictring的具体类。

 public interface Demo
    {
        int PredictRating(int param1);
    }
    public abstract class AbstractDemo : Demo
    {
        public virtual int PredictRating(int param1)
        {
            return param1 + 1;
        }
    }
    public class ClassDemo1 : AbstractDemo
    {
        //This guy uses AbstractDemo Predict Rating
        public override int PredictRating(int param1)
        {
            return base.PredictRating(param1);
        }
    }
    public class ClassDemo2 : AbstractDemo
    {
        //This guy overrides the predict rating behavior
        public override int PredictRating(int param1)
        {
            return param1 + 2;
        }
    }

您必须实现这四个方法。它们具有不同的特征,因此被认为是不同的。然而,你可以有一个委托给另一个,有时使用显式实现有助于这一点。

public class Foo : IBiasSvdPredictor {
    public float PredictRating(IBiasSvdModel, string user, string artist) { .... }
    // this is an expicit implementation of ISvdPredictor's method. You satisfy
    // the interface, but this method is not a public part of the class. You have to
    // cast the object to ISvdPredictor in order to use this method.
    float ISvdPredictor.PredictRating(ISvdModel model, string user, string artist) {
        this.PredictRating((IBiasSvdModel)model, user, artist);
    }
}

如果ISvdModel实际上不是IBiasSvdModel,这当然不起作用。

您可以使用显式接口实现来隐藏ISvdPredictor的接口,但您应该实现它们全部或有一个基本抽象类来处理它们

我必须实现两对PredictRating方法。

你当然知道。你想要什么?

如果您的IBiasSvdPredictor 必须在其PredictRating方法中取IBiasSvdModel,则IBiasSvdPredictor而不是ISvdPredictor(因为它不能将ISvdModel作为PredictRating的第一个参数),从ISvdPredictor继承IBiasSvdPredictor是错误的选择。

在我看来,你应该简单地保持接口的分离,而不是从另一个继承。

如果没有对对象模型的充分理解(因此这实际上可能不适用于您的情况),似乎ISvdModel不应该是接口定义的一部分。它看起来更像是一个实现细节,而不一定是您试图执行的契约的一部分。对我来说,将ISvdModel(或IBiasSvdModel)传递到实现类的构造函数中更有意义,而不是将其作为ISvdPredictor接口的一部分。那么你根本不需要两个单独的接口定义,你只需要一个接口的两个实现。

你甚至可以更进一步;如果ISvdPredictorIBiasSvdPredictor之间的唯一区别是一个使用ISvdModel,另一个使用IBiasSvdModel,那么您甚至不需要两个实现,只需一个,并且您将为每种情况传递正确的ISvdModel实例。这是一种称为控制反转的设计模式,特别是使用依赖注入,它非常强大,可以在程序中实现更高级别的代码重用。