C#中的继承问题

发布于 2024-11-30 12:41:44 字数 1645 浏览 1 评论 0原文

我正在重构一些代码,并希望继承链中更高一点的类对其参数更加严格。由于我不确定我是否正确解释了这一点,这就是我所得到的:

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

它使用 IBiasSvdModel 派生自 ISvdModel

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

IBiasSvdPredictor 不适用于 ISvdModel

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

我也尝试过泛型,但无法使用 whereBiasSvdPredictorPredictRating 限制为 IBiasSvdModel指示。我可能做错了所以任何建议可能会有所帮助。我想你明白我想做的事。

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

I'm refactoring some code and want to classes a bit higher in the inheritance chain be a bit more strict with their parameters. As I'm not sure I'm explaining this correctly, here's what I've got:

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 uses ISvdModel:

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

Now I want to implement another variation:

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

Which uses IBiasSvdModel which derives from ISvdModel:

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

IBiasSvdPredictor will not work with ISvdModel.

The problem is that when I implement IBiasSvdPredictor I'd have to implement 2 pairs of PredictRating methods. One from ISvdPredictor and the other from IBiasSvdPredictor. What do I need to do to be able to just implement those from IBiasSvdPredictor?

I've tried generics as well, but couldn't restrict the PredictRating for BiasSvdPredictor to IBiasSvdModel using the where directive. I may be doing this all wrong so any suggestion might help. I think you get what I'm trying to do.

EDIT: If anyone needs more context see https://github.com/gligoran/RecommendationSystem. I'm writing this code for my thesis for BSc.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

悲喜皆因你 2024-12-07 12:41:44

您可以使用泛型和约束。

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) { }
}

You could use generics and constraints.

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) { }
}
挽袖吟 2024-12-07 12:41:44

接口应该有一个方法,PredictRating。我不会有两个具有相同方法来实现的接口。令人困惑。

创建一个实现您的接口抽象类。将 PredictRating 设为虚拟方法,以便继承者可以根据需要进行重写。您甚至可以对抽象类进行默认实现。

一个接口,一个抽象类。 N 个具体类,按照他们认为合适的方式实现 PredictRating。

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

The interface should have one method, PredictRating. I wouldn't have two interfaces that have the same method to implement. Confusing.

Create an abstract class that implements your interface. Make PredictRating a virtual method so inheritors can override as they see fit. You could even do a default implementation on the abstract class.

One interface, One abstract class. N concrete class that implement PredictRating as they see fit.

 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;
        }
    }
情绪操控生活 2024-12-07 12:41:44

您必须实现所有四种方法。它们具有不同的签名,因此被认为是不同的。但是,您可以将一个委托委托给另一个委托,有时使用显式实现会有所帮助。

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,这当然不起作用。

You have to implement all four methods. They have different signatures and thus are considered to be different. However, you can have one delegate to the other, and sometimes using explicit implementation helps with that.

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

This of course will not work if the ISvdModel is not actually an IBiasSvdModel.

回梦 2024-12-07 12:41:44

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

You can use explicit interface implementation to hide the ones from ISvdPredictor, but you should implement them all or have a base abstract class to handle them.

避讳 2024-12-07 12:41:44

我必须实现 2 对 PredictRating 方法。

当然可以。你期待什么?

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

在我看来,您应该简单地将接口分开,而不是继承另一个接口。

I'd have to implement 2 pairs of PredictRating methods.

Of course you do. What did you expect?

If your IBiasSvdPredictor must take a IBiasSvdModel in its PredictRating method, than IBiasSvdPredictor is not an ISvdPredictor (because it cannot take a ISvdModel as the first parameter to PredictRating) and inheriting IBiasSvdPredictor from ISvdPredictor is the wrong choice.

In my opinion, you should simply keep the interfaces separate and not inherit one from the other.

无敌元气妹 2024-12-07 12:41:44

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

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

Without having a full understanding of your object model (so this may not actually apply in your situation), it seems like maybe ISvdModel shouldn't be part of the interface definition. It seems more like it's an implementation detail, not necessarily part of the contract you're trying to enforce. To me it makes more sense to pass ISvdModel (or IBiasSvdModel) into the constructor of your implementation class, not have it as part of your ISvdPredictor interface. Then you wouldn't need 2 separate interface definitions at all, you would just have 2 implementations of the single interface.

You might even be able to take it one step further; if the only difference between ISvdPredictor and IBiasSvdPredictor is that one uses a ISvdModel and the other uses a IBiasSvdModel, you wouldn't even need 2 implementations, just one, and you would pass in the correct instance of ISvdModel for each situation. This is a design pattern called Inversion of Control, specifically using Dependency Injection, and is very powerful to achieve higher levels of code reuse in your programs.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文