【问题标题】:How to restrict passed parameter in method如何限制方法中传递的参数
【发布时间】:2015-03-17 11:49:09
【问题描述】:

我的问题是在示例代码中。 我如何限制开发人员传递真实参数。我尝试了一些关于泛型的方法,但我无法修复。

这里重要的是我想限制编译时间。所以我知道如何在运行时进行预防。

namespace TheLiving
{
    public interface IFood
    {
        int Protein { get; set; }
        int Carbohydrate { get; set; }
    }

    public interface IMeat : IFood
    {
        int Nitrogen { get; set; }
    }

    public interface IVegetable : IFood
    {
        int Vitamin { get; set; }
    }


    public class Veal : IMeat
    {
        public int Protein { get; set; }
        public int Carbohydrate { get; set; }
        public int Nitrogen { get; set; }
    }

    public class Spinach : IVegetable
    {
        public int Protein { get; set; }
        public int Carbohydrate { get; set; }
        public int Vitamin { get; set; }
    }

    public interface IEating
    {
        void Eat(IFood food);
    }

    public class Lion : IEating
    {
        public int Protein { get; set; }
        public int Carbohydrate { get; set; }
        public int Nitrogen { get; set; }


        //But lion is eating only Meat. So any developer can pass vegatable to lion for eating. 
        //May be god is not a good developer. So i want restrict him on Compile Time!! for passing only Meat. :)
        //The important thing here is i want restrict on Compile Time not RunTime!!!
        public void Eat(IFood food)
        {
            Protein = food.Protein;
            Carbohydrate = food.Carbohydrate;
            //Nitrogen = ?? //So i know that i can cast and validate food but i want ensure this on DesignTime!!
        }
    }

    public class Sheep : IEating
    {
        public int Protein { get; set; }
        public int Carbohydrate { get; set; }
        public int Vitamin { get; set; }

        public void Eat(IFood food)
        {
            Protein = food.Protein;
            Carbohydrate = food.Carbohydrate;
            //Vitamin = food.??
        }
    }
}

【问题讨论】:

  • 这种设计是不可能的,只能在运行时抛出异常。
  • 我认为你的意思是 compile time 而不是 design time
  • @Oliver 是的编译时间。谢谢指正。

标签: c# design-patterns methods parameter-passing restrict


【解决方案1】:

我认为您必须拥有IHerbivoreICarnivoreIOmnivore 的接口才能在设计时允许这样做。

public interface IHerbivore
{
    void Eat(IVegetable food);
}

public interface ICarnivore
{
    void Eat(IMeat food);
}

public interface IOmnivore : IHerbivore, ICarnivore
{
}

那么你的狮子可以是ICarnivore,只能吃肉

【讨论】:

  • 是的,它更好地解决了这个问题。谢谢。但在我的项目中,我无法更改设计。我认为可能有一种使用泛型的方法。类似的东西 void Eat(T food) where T : IMeat;
  • 我不明白,您可以将 Eat 的设计更改为通用但您不能更改设计以引入几个新界面?
【解决方案2】:

或者你可以改变界面...

public interface IEating
{
    bool Eat(IFood food); //return wheater the eater eats the food or not
}

然后像这样实现狮子:

public class Lion : IEating
{
    public int Protein { get; set; }
    public int Carbohydrate { get; set; }
    public int Nitrogen { get; set; }

    public bool Eat(IFood food)
    {
        IMeat meat = food as IMeat;
        if (meat != null)
        {

            Protein = meat.Protein;
            Carbohydrate = meat.Carbohydrate;
            Nitrogen = meat.Nitrogen;
            return true;
        }
        return false;
    }
}

【讨论】:

  • 不错的选择,但这仍然只提供运行时验证,而不是设计时验证。它向程序员表明食物可能不会被吃掉,但他们需要满足这种可能性。
  • @SamHolder 完全正确,只是想指出另一种设计方法
【解决方案3】:
public interface IEating<in T> where T : IFood {

    void Eat(T food);
}

public class Lion : IEating<IMeat>, IEating<IFood> {

    public int Protein { get; set; }
    public int Carbohydrate { get; set; }
    public int Nitrogen { get; set; }

    public void Eat(IMeat food) {

        Protein = food.Protein;
        Carbohydrate = food.Carbohydrate;
        Nitrogen = food.Nitrogen;
    }

    public void Eat(IFood food) {

        var meat = food as IMeat;
        if (meat == null) return;

        Eat(meat);
    }
}

public class Sheep : IEating<IVegetable>, IEating<IFood> {

    public int Protein { get; set; }
    public int Carbohydrate { get; set; }
    public int Vitamin { get; set; }

    public void Eat(IVegetable food) {
        Protein = food.Protein;
        Carbohydrate = food.Carbohydrate;
        Vitamin = food.Vitamin;
    }

    public void Eat(IFood food) {

        var vegetable = food as IVegetable;
        if (vegetable == null) return;

        Eat(vegetable);
    }
}

【讨论】:

  • 您的代码没有 cmets。尝试添加解释性文字。
【解决方案4】:

MS Code Contracts 呢?我发誓它的 Visual Studio 集成至少会在编译时添加警告。

【讨论】:

    猜你喜欢
    • 2017-04-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-19
    • 2017-03-16
    相关资源
    最近更新 更多