替代特征
Alternative to traits
我是从 PHP 开始接触 C# 的新手,我遇到了一个问题,哪些特征是完美的,但我知道 C# 不支持特征。解决此问题的最佳方法是什么?
在 Godot 中,我想通过添加一些动画方法来让自己更轻松地制作动画,根据 PHP 我会做这样的事情。这些方法也不能真正是静态的。
public trait SpriteAnimator {
public void Animate(string animation)
{
// DO SOMETHING
}
}
public class Actor : KinematicBody2D
{
use SpriteAnimator;
public override void _Ready()
{
Animate("run");
}
}
我如何在 C# 中解决这个问题?
这来自 Jordão。我不知道您在静态方法中获得了调用它的对象。
C# 没有任何与 PHP 的 trait
系统完全相似的东西,但它的某些方面可以使用 interface
s、扩展方法和偶尔的默认接口来模拟方法。
trait
最简单的用法是向 class 中添加方法,而无需 subclassing。扩展方法允许您根据对象的类型有效地向对象添加方法。只有在目标类型上公开可见的成员才能在扩展中访问。
public interface INamed
{
string Name { get; }
}
public static class DemoExtensions
{
// This is available on instances of any type
public static void SayHello(this object self)
{
Console.WriteLine("Hello.")
}
// This one will work on instances whose type implements INamed
public static void SayHello(this INamed self)
{
Console.WriteLine($"Hello {self.Name}.");
}
}
静态trait
数据成员更难。虽然您可以在扩展 class(上面的 DemoExtensions
)中定义静态字段或 属性,但该值在运行扩展方法的所有类型之间共享。如果您需要基于调用该方法的对象类型的静态值,那么您需要在扩展 class.
中使用 Dictionary<type, ...>
static 手动处理该值
另一个限制是扩展方法需要一个对象来调用:
public class MyClass : INamed
{
public string Name { get; }
public MyClass(string name)
{
Name = name;
}
public void DoSomething()
{
this.SayHello();
}
}
注意 DoSomething
中的 this.SayHello();
行。如果去掉 this.
部分,程序将无法编译。
默认接口方法也可以用作一种扩展,但是在访问它们之前必须将类型强制转换为接口。不再是 this.SayHello();
,现在是 ((INamed)this).SayHello();
,这还不是最糟糕的。他们有自己的位置,但大多数情况下对我没有用。您的里程可能会有所不同。
从 C#9 开始,除了方法之外,没有其他方法可以添加扩展类型,我非常怀疑我们在未来的任何时候都不会获得扩展属性。在这种情况发生变化之前,您必须自己想办法解决 trait
属性。
我是从 PHP 开始接触 C# 的新手,我遇到了一个问题,哪些特征是完美的,但我知道 C# 不支持特征。解决此问题的最佳方法是什么?
在 Godot 中,我想通过添加一些动画方法来让自己更轻松地制作动画,根据 PHP 我会做这样的事情。这些方法也不能真正是静态的。
public trait SpriteAnimator {
public void Animate(string animation)
{
// DO SOMETHING
}
}
public class Actor : KinematicBody2D
{
use SpriteAnimator;
public override void _Ready()
{
Animate("run");
}
}
我如何在 C# 中解决这个问题?
C# 没有任何与 PHP 的 trait
系统完全相似的东西,但它的某些方面可以使用 interface
s、扩展方法和偶尔的默认接口来模拟方法。
trait
最简单的用法是向 class 中添加方法,而无需 subclassing。扩展方法允许您根据对象的类型有效地向对象添加方法。只有在目标类型上公开可见的成员才能在扩展中访问。
public interface INamed
{
string Name { get; }
}
public static class DemoExtensions
{
// This is available on instances of any type
public static void SayHello(this object self)
{
Console.WriteLine("Hello.")
}
// This one will work on instances whose type implements INamed
public static void SayHello(this INamed self)
{
Console.WriteLine($"Hello {self.Name}.");
}
}
静态trait
数据成员更难。虽然您可以在扩展 class(上面的 DemoExtensions
)中定义静态字段或 属性,但该值在运行扩展方法的所有类型之间共享。如果您需要基于调用该方法的对象类型的静态值,那么您需要在扩展 class.
Dictionary<type, ...>
static 手动处理该值
另一个限制是扩展方法需要一个对象来调用:
public class MyClass : INamed
{
public string Name { get; }
public MyClass(string name)
{
Name = name;
}
public void DoSomething()
{
this.SayHello();
}
}
注意 DoSomething
中的 this.SayHello();
行。如果去掉 this.
部分,程序将无法编译。
默认接口方法也可以用作一种扩展,但是在访问它们之前必须将类型强制转换为接口。不再是 this.SayHello();
,现在是 ((INamed)this).SayHello();
,这还不是最糟糕的。他们有自己的位置,但大多数情况下对我没有用。您的里程可能会有所不同。
从 C#9 开始,除了方法之外,没有其他方法可以添加扩展类型,我非常怀疑我们在未来的任何时候都不会获得扩展属性。在这种情况发生变化之前,您必须自己想办法解决 trait
属性。