C# 将类方法移到泛型实现中
我正在尝试重构一些代码,不得不承认我对泛型的概念还不熟悉 我有一个基本类: BaseVarDef.cs:C# 将类方法移到泛型实现中,c#,unity3d,generics,C#,Unity3d,Generics,我正在尝试重构一些代码,不得不承认我对泛型的概念还不熟悉 我有一个基本类: BaseVarDef.cs: using UnityEngine; public abstract class BaseVarDef<T> : ScriptableObject { [Multiline] public string DeveloperDescription = ""; public T Value; public void SetValue(T value
using UnityEngine;
public abstract class BaseVarDef<T> : ScriptableObject
{
[Multiline]
public string DeveloperDescription = "";
public T Value;
public void SetValue(T value)
{
Value = value;
}
}
然后我有几个类是从这个派生出来的。但它们都包含相同的3个方法,我想将它们重构成这个通用基类。唯一的区别是它们期望当前定义它们的泛型类型或类
浮动变量
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
提前感谢我想您可以在基类中定义所有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;
}
}
我认为您可以在基类中定义所有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;
}
}
如果只需将这些方法添加到原始基类中,然后从中删除抽象,然后只需执行BaseVarDef或BaseVarDef。不再需要FloatVar或StringVar类 这里需要技巧的部分是+=运算符,它不能应用于泛型,至少我知道没有允许您指定实现运算符的类型的约束 因此,您可以创建一个抽象的Add方法,派生类必须按照Svetlana描述的那样实现该方法,也可以使用如下所示的动态方法,完全不需要派生类 动态的一个问题是,动态类型没有编译时检查,因此它不是万无一失的。类型T必须重载+运算符,否则将出现运行时异常。您可以通过包装行值=amt+val来避免这种情况;在一次尝试中,你可能会得到意想不到的行为
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 { }
}
}
如果只需将这些方法添加到原始基类中,然后从中删除抽象,然后只需执行BaseVarDef或BaseVarDef。不再需要FloatVar或StringVar类 这里需要技巧的部分是+=运算符,它不能应用于泛型,至少我知道没有允许您指定实现运算符的类型的约束 因此,您可以创建一个抽象的Add方法,派生类必须按照Svetlana描述的那样实现该方法,也可以使用如下所示的动态方法,完全不需要派生类 动态的一个问题是,动态类型没有编译时检查,因此它不是万无一失的。类型T必须重载+运算符,否则将出现运行时异常。您可以通过包装行值=amt+val来避免这种情况;在一次尝试中,你可能会得到意想不到的行为
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。这使您不必为每种类型定义派生类;如果类型T未实现+运算符,则将引发运行时异常。你可以用try/catch来包装它,但是Svetlana的回答以一种更安全的方式来处理这个问题——强制客户端实现AddValue方法。我重新阅读了你的问题,现在明白你想要组合这些类,所以我修改了上面的答案。然后派生:FloatVar,StringVar,BaseBarDefExt类中的etc?您不再需要FloadVar…只需要BaseBarDefExt。这使您不必为每种类型定义派生类;如果类型T未实现+运算符,则将引发运行时异常。你可以用try/catch来包装它,但是Svetlana的回答以一种更安全的方式来处理这个问题——强制客户端实现AddValue方法。我重新阅读了你的问题,现在明白你想要组合这些类,所以我修改了上面的答案。我认为这是解决这个问题的最好办法,特别是因为我想说你应该把孩子们分开。AddValue处理浮点数和字符串的方式非常不同,因此将该操作声明为抽象操作并让子类处理它是有意义的;通过这种方式,您可以在以后以完全不同的方式实现另一个AddValue类,而无需使用+=运算符。我认为这是解决此问题的最佳解决方案,特别是因为我认为您应该将子类分开。AddValue处理浮点数和字符串的方式非常不同,因此将该操作声明为抽象操作并让子类处理它是有意义的;通过这种方式,您可以在以后以完全不同的方式实现另一个AddValue类,而无需使用+=运算符。