【问题标题】:Property set, null in other class. C#属性集,在其他类中为空。 C#
【发布时间】:2019-02-06 00:19:27
【问题描述】:

好吧,我不知道为什么会这样。

我设置了一个属性,在我设置它之后,它在另一个类中为空。使用调试器单步执行它只会显示它已设置,并且它在其他类中为 null。

这是我的代码:(去掉所有不必要的代码)

public class SnakeGame : SenseHatSnake, ISnakeGame
{
    private readonly IBody _body;

    public SnakeGame(ISenseHat senseHat, IBody body)
        : base(senseHat)
    {
        _body = body;
    }

    private void UpdateGame(Object state)
    {

        _movement.PreviousPositions.Add(new Position()
        {
            X = _movement.X,
            Y = _movement.Y
        });

        if (_body.DetectCollision(_movement.X, _movement.Y))
        {
            GameOver();
        }
    }
}

它发生在 body 类中的 DetectCollision

public class Body : IBody
    {    
        private readonly IMovement _movement;

        public Body(IMovement movement)
        {
            _movement = movement;
        }

        public bool DetectCollision(int x, int y)
        {
            for (int i = 1; i < Length + 1; i++)
            {
                if (_movement.PreviousPositions.Count > i)
                {
                    int bX = _movement.PreviousPositions[_movement.PreviousPositions.Count - i - 1].X;
                    int bY = _movement.PreviousPositions[_movement.PreviousPositions.Count - i - 1].Y;

                    if (bX == x && bY == y)
                    {
                        return true;
                    }
                }
            }

            return false;
        }

    }

我刚刚设置了_movement.PreviousPositions,我可以在调试器中看到它,但只要它在Body 中,_movement.PreviousPositions 就为空。

Movement.cs:

public class Movement : IMovement
{
    public List<Position> PreviousPositions { get; set; }      
}

注意:

我正在使用 DI,我在那里做错了吗? (Autofac)

public sealed partial class MainPage : Page
{
    public MainPage()
    {
        this.InitializeComponent();



        var builder = new ContainerBuilder();
        builder.RegisterType<Body>().As<IBody>();
        builder.RegisterType<Display>().As<IDisplay>();
        builder.RegisterType<Draw>().As<IDraw>();
        builder.RegisterType<Food>().As<IFood>();
        builder.RegisterType<Movement>().As<IMovement>();
        builder.RegisterType<SnakeGame>().As<ISnakeGame>();
        builder.RegisterType<ISenseHat>().As<ISenseHat>();
        var container = builder.Build();

        var body = container.Resolve<IBody>();
        var display = container.Resolve<IDisplay>();
        var draw = container.Resolve<IDraw>();
        var food = container.Resolve<IFood>();
        var movement = container.Resolve<IMovement>();

        Task.Run(async () =>
        {
            ISenseHat senseHat = await SenseHatFactory.GetSenseHat().ConfigureAwait(false);
            var snakeGame = new SnakeGame(senseHat, body, display, draw, food, movement);
            snakeGame.Run();
        });


    }


}

【问题讨论】:

  • PreviousPositions 在运动中。 (将该类添加到问题中)
  • SnakeGame 没有在您的问题中定义 _movement,因此尚不清楚这与 _body 有何关系。
  • 尝试在PreviousPositions的设置器中设置断点。
  • @SelmanGenç 我做了,它已经设置好了。
  • 如果您假设Body 将获得与SnakeGame 相同的IMovement,那是不正确的。 Autofac 的默认注册是InstancePerDependency,所以BodySnakeGame 将各自获得自己独特的Movement 实例。这是这里的问题吗?

标签: c# dependency-injection uwp autofac


【解决方案1】:

默认情况下,Autofac 将组件注册为InstancePerDependency,因此这段代码将获得两个唯一的实例:

var a = container.Resolve<IExample>();
var b = container.Resolve<IExample>();

如果你想要一个单例,你需要使用.SingleInstance()注册对象:

builder.RegisterType<Movement>().As<IMovement>().SingleInstance();

这应该可以解决您的问题,尽管我注意到您似乎通过手动解析每个服务来使用 service locator anti-pattern。你可以把你的代码改成这样:

var builder = new ContainerBuilder();
builder.RegisterType<Body>().As<IBody>();
builder.RegisterType<Display>().As<IDisplay>();
builder.RegisterType<Draw>().As<IDraw>();
builder.RegisterType<Food>().As<IFood>();
builder.RegisterType<Movement>().As<IMovement>().SingleInstance();
builder.RegisterType<SnakeGame>().As<ISnakeGame>();
builder.RegisterInstance<ISenseHat>(await SenseHatFactory.GetSenseHat().ConfigureAwait(false));

var container = builder.Build();

var snakeGame = container.Resolve<ISnakeGame>();
snakeGame.Run();

【讨论】:

    【解决方案2】:

    RegisterType 将在请求类型时解析为新实例。如果您想在您的类之间共享一个实例,请使用 RegisterInstance 代替您的 Movement 类,例如

            var movement = new Movement();
            var builder = new ContainerBuilder();
            builder.RegisterType<Body>().As<IBody>();
            builder.RegisterType<Display>().As<IDisplay>();
            builder.RegisterType<Draw>().As<IDraw>();
            builder.RegisterType<Food>().As<IFood>();
            **builder.RegisterInstance<IMovement>(movement);**
            builder.RegisterType<SnakeGame>().As<ISnakeGame>();
            builder.RegisterType<ISenseHat>().As<ISenseHat>();
            var container = builder.Build();
    

    【讨论】:

    • 这是一个糟糕的解决方案,因为这会阻止您在通过 RegisterInstance 添加的类型中使用依赖注入。注册类型并调用.SingleInstance() 将允许您仍然将服务注入单例实例。不过感谢您的反对:)
    • RegisterInstance 存在是有原因的——专门解决这些类型的问题。依赖注入的存在是为了在一个地方维护您的依赖关系图和实例管理。请支持您的评论并用一个很好的解释投票。
    • 我已经提供了很好的解释。实际上,我在自己的示例中使用了RegisterInstance - 注册外部服务提供的实例。如果 OP 使用 Movement 类中的任何注入服务,则 OP 不能使用 RegisterInstance 注册它。就这么简单。 .SingleInstance() 就是为了解决这个问题而创建的。
    • 您有任何证据支持RegisterInstance 是这里的最佳解决方案吗? :)
    • 所以说用就不好用?而且因为你说要使用它,这是合理的吗?从您的解释的角度来看,单例如何比单个实例更好。我不确定您是否对 DI 有正确的理解 - 或者 - 您只是喜欢对其他帮助社区的人投反对票 :)
    猜你喜欢
    • 1970-01-01
    • 2020-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-11
    • 1970-01-01
    相关资源
    最近更新 更多