【问题标题】:Moving like methods into generic implementation将类似的方法移动到通用实现中
【发布时间】:2019-03-29 04:36:54
【问题描述】:

我正在尝试重构一些代码,并且不得不承认我对泛型的概念不熟悉。

我有一个基类:

BaseVarDef.cs:

using UnityEngine;
public abstract class BaseVarDef<T> : ScriptableObject
{
    [Multiline]
    public string DeveloperDescription = "";

    public T Value;

    public void SetValue(T value)
    {
        Value = value;
    }

}

然后我有几个由此派生的类。但它们都包含相同的 3 个方法,我想将它们重构为这个通用基类。唯一的区别是他们期望当前定义它们的泛型类型或类。

FloatVar.cs

using UnityEngine;
[CreateAssetMenu(fileName = "New FloatVar", menuName = "Variables/FloatVar")]
public class FloatVar : BaseVarDef<float>
{
    public void SetValue(FloatVar value)
    {
        Value = value.Value;
    }
    public void ApplyChange(float amount)
    {
        Value += amount;
    }
    public void ApplyChange(FloatVar amount)
    {
        Value += amount.Value;
    }
}

StringVar.cs

using UnityEngine;
[CreateAssetMenu(fileName = "New StringVar", menuName = "Variables/StringVar")]
public class StringVar : BaseVarDef<string>
{
    public void SetValue(StringVar value)
    {
        Value = value.Value;
    }
    public void ApplyChange(string amount)
    {
        Value += amount;
    }
    public void ApplyChange(StringVar amount)
    {
        Value += amount.Value;
    }
}

有没有办法将 SetValue 和 2 个重载的 ApplyChange 方法重构为 BaseVarDef.cs?

提前致谢

【问题讨论】:

    标签: c# unity3d generics


    【解决方案1】:

    我认为你可以在基类中定义所有的 Apply 和 Set

    public abstract class BaseVarDef<T>
    {
        public string DeveloperDescription = "";
    
        public T Value;
    
        public void SetValue(T value)
        {
            Value = value;
        }
        public void SetValue(BaseVarDef<T> value)
        {
            Value = value.Value;
        }
        public void ApplyChange(T amount)
        {
            AddValue(amount);
        }
        public void ApplyChange(BaseVarDef<T> amount)
        {
            AddValue(amount.Value);
        }
    
        protected abstract void AddValue(T val);
    }
    
    public class FloatVar : BaseVarDef<float>
    {
        protected override void AddValue(float val)
        {
            Value += val;
        }
    }
    

    【讨论】:

    • 我认为这是解决此问题的最佳解决方案,特别是因为我会说您应该将子类分开。 AddValue 对浮点数和字符串的工作方式非常不同,因此将该操作声明为抽象并让子类处理它是有意义的;这样,您以后可能会实现其他一些以完全不同的方式执行 AddValue 的类,而无需使用 += 运算符。
    【解决方案2】:

    如果您可以将这些方法添加到原始基类(然后从中删除abstract),那么您只需执行BaseVarDef&lt;string&gt;BaseVarDef&lt;float&gt;。不再需要 FloatVarStringVar 类!

    这里棘手的部分是+= 运算符,它不能应用于泛型(至少我知道没有约束允许您指定类型实现运算符)。

    因此,您可以创建一个抽象的Add 方法,派生类必须按照 Svetlana 的描述实现该方法,或者您可以使用dynamic,如下所示(并且完全不需要派生类)。

    dynamic 的一个问题是dynamic 类型没有编译时检查,所以它不是万无一失的。 T 类型必须重载 + 运算符,否则会出现运行时异常。您可以通过将行 Value = amt + val; 包装在 try/catch 中来避免这种情况,但随后您可能会得到意外行为。

    public class BaseVarDef<T>
    {
        public string DeveloperDescription { get; set; } = "";
    
        public T Value { get; private set; }
    
        public void SetValue(T value)
        {
            Value = value;
        }
    
        public void SetValue(BaseVarDef<T> value)
        {
            Value = value.Value;
        }
    
        public void ApplyChange(T amount)
        {
            AddToValue(amount);
        }
    
        public void ApplyChange(BaseVarDef<T> amount)
        {
            AddToValue(amount.Value);
        }
    
        private void AddToValue(T amount)
        {
            dynamic amt = amount;
            dynamic val = Value;
    
            // Empty catch to avoid runtime exception if 'T' doesn't support the '+' operator
            try { Value = amt + val; }
            catch { }           
        }
    }
    

    【讨论】:

    • 然后从 BaseBarDefExt 类中派生出:FloatVar、StringVar 等?
    • 您不再需要FloadVar...只需BaseVarDefExt&lt;float&gt;。这使您不必为每种类型定义派生类。
    • 请注意这是危险的,因为如果T 类型没有实现+ 运算符,Value = amt + val; 行将引发运行时异常。您可以将其包装在 try/catch 中,但 Svetlana 的答案以更安全的方式处理此问题 - 强制客户端实现 AddValue 方法。
    • 我重新阅读了你的问题,现在明白你想合并这些类,所以我修改了上面的答案。
    猜你喜欢
    • 2011-03-19
    • 1970-01-01
    • 2017-10-17
    • 2020-07-27
    • 2011-04-07
    • 1970-01-01
    • 1970-01-01
    • 2010-10-23
    • 2021-12-06
    相关资源
    最近更新 更多