【问题标题】:Modifier System C#修饰符系统 C#
【发布时间】:2011-03-19 07:11:54
【问题描述】:

我正在尝试找出一个可以轻松地动态修改对象的系统。

这是一个例子,假设我有一个继承自 Entity 的 Entity2D。 Entity2D 有一个 Position 属性。

现在我有一个名为 ModifyPosition 的类,它继承自 Modifier。

这是一些代码

public class Entity
{
/// <summary>
/// Applies the modifier to this entity.
/// </summary>
/// <param name="modifier">The modifier to apply.</param>
public void ApplyModifier(Modifier modifier)
{
    modifier.Apply(this);
}
}

/// <summary>
/// Modifies an entities position
/// </summary>
public class ModifyPosition : Modifier
{
    /// <summary>
    /// Initializes a new instance of the <see cref="ChangePosition"/> class.
    /// </summary>
    /// <param name="position">The position.</param>
    public ChangePosition(Vector2 position)
    {
        this.Position = position;
        this.IsModifyingChildren = false;
    }

    /// <summary>
    /// Gets the position.
    /// </summary>
    /// <value>The position.</value>
    public Vector2 Position { get; private set; }

    /// <summary>
    /// Applies this change to the specified entity.
    /// </summary>
    /// <param name="entity">The entity.</param>
    internal override void Apply(Entity entity)
    {
        ((Entity2D)entity).X += this.Position.X;
        ((Entity2D)entity).Y += this.Position.Y;
    }
}

但如果你每秒调用多次,我认为强制转换会减慢它。

有没有其他方法可以解决这个问题而不必强制转换?

【问题讨论】:

  • 你做了什么,删除并重新提出问题?不是获得答案的好方法
  • 让一个对象出现并从外部修改一个对象可能很奇怪(并且可以说违反了几个准则)。有什么理由需要这样做,而不是将修改代码放在对象内部?
  • @Lucas 它是一个继承者... =/ 我没有阅读发布的答案,所以我试图重新问它...对不起。你之前回答过吗?你介意重新发布你的答案吗?再次抱歉,这是我的错误。 @silky我在想,如果我有办法从外部修改对象,它会更容易像在编辑器中那样动态更改对象的属性。
  • @Chris:在其中构建修改过程几乎总是更好。原因是您可以在类中编写特定于类的代码,并且您可以访问私有功能等。考虑更改使用这种方法,我基本上保证你的生活会更好,你的代码会更容易理解:)
  • 我认为 Entity 最好有一个 Apply(IModifier modifier) 方法。 entity.Apply(moveToNewPosition) 看起来更有用

标签: c# game-engine access-modifiers


【解决方案1】:

如果你使用接口 IEntity

interface IEntity
{
 double X{get;}
 double Y{get;}
}

让实体实现该接口

public class Entity: IEntity
{
...
}

并将其用作 Apply 的参数类型

internal override void Apply(IEntity entity)
    {
        entity.X += this.Position.X;
        entity.Y += this.Position.Y;
    }

那你就不用投了

【讨论】:

    【解决方案2】:

    使用 C#,您必须确保您正在修改的类型支持您的修改(某些语言并非如此)。所以你的修饰符必须明确知道他们正在修改哪些类型。 (或者,您的实体可以知道修饰符,但将知识提供给修饰符似乎更合理。)

    在这一点上,我实际上没有答案;这是我的尝试,但在 ModifyPosition.Apply 声明中出现编译器错误,指出您无法在重写的方法实现上指定类型约束。

    public interface IPositionableEntity
    {
        Vector2 Position { get; set; }
    }
    
    public class Entity
    {
        public void ApplyModifier<T>(T modifier) where T : Modifier 
        {
            modifier.Apply(this);
        }
    }
    
    public class Entity2D : Entity, IPositionableEntity
    {
        public Vector2 Position { get; set; }
    }
    
    public class Vector2
    {
        public double X { get; set; }
        public double Y { get; set; }
    }
    
    public abstract class Modifier
    {
        public abstract void Apply<T>(T entity);
    }
    
    public class ModifyPosition : Modifier
    {
        public ModifyPosition(Vector2 position)
        {
            Position = position;
        }
    
        public Vector2 Position { get; private set; }
    
        //Compiler error here:
        //Constraints for explicit interface implementation method are inherited
        //from the base method, so they cannot be specified directly
        public override void Apply<T>(T entity) where T : IPositionableEntity
        {
            entity.Position.X += Position.X;
            entity.Position.Y += Position.Y;
        }
    }
    

    EDIT - 这是至少可以编译的。唯一的变化是 ModifyPosition。

    public class ModifyPosition : Modifier
    {
        public ModifyPosition(Vector2 position)
        {
            Position = position;
        }
    
        public Vector2 Position { get; private set; }
    
        public override void Apply(object entity)
        {
            if (!(entity is IPositionableEntity))
            {
                return; //throw, whatever
            }
    
            var positionableEntity = (IPositionableEntity) entity;
            positionableEntity.Position.X += Position.X;
            positionableEntity.Position.Y += Position.Y;
        }
    }
    

    【讨论】:

    • 有趣,这可能有效,但是当一个类开始有很多你想要更改的属性时,它可能会增加很多接口。
    • 查看我对您的问题的评论 - 我认为在 C# 中无法像您希望的那样通用地解决这个问题。
    【解决方案3】:

    试试这样的:

    class CatEntity : Entity, IModifiablePosition
    {
      // Interface method
      public void ModifyPosition(Vector2 blah) { ... }
    ...
    }
    
    
    class RobotEntity : Entity, IModifiableShader, IModifiablePosition
    {
    // Interface method
    public void PushShader(RobotEffect bleh) { ... }
    public void ModifyPosition(Matrix blah) { ... }
    ...
    }
    
    class ShaderModifier : IModifier
    {
      public override void Apply(IModifiableShader obj)
      {
        obj.PushShader(m_furryEffect);
      }
    }
    
    class PositionModifier : IModifier
    {
      public override void Apply(IModifiablePosition obj)
      {
        obj.ModifyPosition(m_mxTranslation);
      }
    }
    

    这看起来很容易阅读和安全——希望它对你有用。

    【讨论】:

      猜你喜欢
      • 2022-06-16
      • 2012-08-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-23
      • 2011-06-13
      • 2015-04-11
      • 1970-01-01
      相关资源
      最近更新 更多