c#泛型,类型略有不同?

c#泛型,类型略有不同?,c#,generics,C#,Generics,请注意两个扩展,一个用于float,一个用于Vector3 请注意,var(调用)中只有一点不同 在c#中,这些可以作为一个泛型来编写吗 我的问题的实质是: 在泛型中,您可以对类型的性质进行分支吗? (如果您不熟悉Unity并且不熟悉扩展的基本概念,这里有一个。)如果您在调用var操作(您应该重命名该操作,因为var是一个C#关键字)之前额外创建一个执行转换的Func,您就可以这样做 以下是您可以采取的一种方法: public static IEnumerator Tweeng<T>

请注意两个扩展,一个用于float,一个用于Vector3

请注意,
var(
调用)中只有一点不同

在c#中,这些可以作为一个泛型来编写吗

我的问题的实质是:

在泛型中,您可以对类型的性质进行分支吗?


(如果您不熟悉Unity并且不熟悉扩展的基本概念,这里有一个。)

如果您在调用
var
操作(您应该重命名该操作,因为
var
是一个C#关键字)之前额外创建一个执行转换的
Func
,您就可以这样做

以下是您可以采取的一种方法:

public static IEnumerator Tweeng<T>(
    this float duration
,   System.Action<T> varAction
,   T aa
,   T zz
) {
    Func<T,T,float,T> transform = MakeTransform<T>();
    float sT = Time.time;
    float eT = sT + duration;
    while (Time.time < eT) {   
        float t = (Time.time-sT)/duration;
        varAction(transform(aa, zz, t));
        yield return null;
    }
    varAction(zz);
}

private static Func<T,T,float,T> MakeTransform<T>() {
    if (typeof(T) == typeof(float)) {
        Func<float, float, float, float> f = Mathf.SmoothStep;
        return (Func<T,T,float,T>)(Delegate)f;
    }
    if (typeof(T) == typeof(Vector3)) {
        Func<Vector3, Vector3, float, Vector3> f = Vector3.Lerp;
        return (Func<T,T,float,T>)(Delegate)f;
    }
    throw new ArgumentException("Unexpected type "+typeof(T));
}
公共静态IEnumerator Tweeng(
此浮动持续时间
,System.Action varAction
,T aa
,T zz
) {
Func transform=MakeTransform();
float sT=Time.Time;
浮动eT=sT+持续时间;
而(Time.Time
它甚至可以内联完成:

public static IEnumerator DasTweeng<T>( this float duration, System.Action<T> vary, T aa, T zz )
    {
    float sT = Time.time;
    float eT = sT + duration;

    Func<T,T,float,T> step;

    if (typeof(T) == typeof(float))
        step = (Func<T,T,float,T>)(Delegate)(Func<float, float, float, float>)Mathf.SmoothStep;
    else if (typeof(T) == typeof(Vector3))
        step = (Func<T,T,float,T>)(Delegate)(Func<Vector3, Vector3, float, Vector3>)Vector3.Lerp;
    else
        throw new ArgumentException("Unexpected type "+typeof(T));

    while (Time.time < eT)
        {
        float t = (Time.time-sT)/duration;
        vary( step(aa,zz, t) );
        yield return null;
        }
    vary(zz);
    }
public static IEnumerator DasTweeng(此浮动持续时间、系统动作变化、T aa、T zz)
{
float sT=Time.Time;
浮动eT=sT+持续时间;
Func步;
如果(类型(T)=类型(浮动))
步骤=(Func)(委托)(Func)数学步骤;
else if(typeof(T)=typeof(Vector3))
步骤=(Func)(委托)(Func)Vector3.Lerp;
其他的
抛出新ArgumentException(“意外类型”+typeof(T));
while(Time.Time
也许更自然的习语是

    Delegate d;

    if (typeof(T) == typeof(float))
        d = (Func<float, float, float, float>)Mathf.SmoothStep;
    else if (typeof(T) == typeof(Vector3))
        d = (Func<Vector3, Vector3, float, Vector3>)Vector3.Lerp;
    else
        throw new ArgumentException("Unexpected type "+typeof(T));

    Func<T,T,float,T> step = (Func<T,T,float,T>)d;
代表d;
如果(类型(T)=类型(浮动))
d=(Func)Mathf.SmoothStep;
else if(typeof(T)=typeof(Vector3))
d=(Func)Vector3.Lerp;
其他的
抛出新ArgumentException(“意外类型”+typeof(T));
Func步骤=(Func)d;

您可以如下定义您的方法:

public static IEnumerator Tweeng<T>(this float duration,
         System.Action<T> var, T aa, T zz, Func<T,T,float,T> thing)
{
    float sT = Time.time;
    float eT = sT + duration;

    while (Time.time < eT)
    {
        float t = (Time.time - sT) / duration;
        var(thing(aa, zz, t));
        yield return null;
    }

    var(zz);
}
或:

或者,如果希望摆脱方法传递,可以使用简单的重载来处理它:

public static IEnumerator Tweeng(this float duration, System.Action<float> var, float aa, float zz)
{
    return Tweeng(duration, var, aa, zz, Mathf.SmoothStep);
}
public static IEnumerator Tweeng(this float duration, System.Action<Vector3> var, Vector3 aa, Vector3 zz)
{
    return Tweeng(duration, var, aa, zz, Vector3.Lerp);
}

private static IEnumerator Tweeng<T>(this float duration,
         System.Action<T> var, T aa, T zz, Func<T,T,float,T> thing)
{
    float sT = Time.time;
    float eT = sT + duration;

    while (Time.time < eT)
    {
        float t = (Time.time - sT) / duration;
        var(thing(aa, zz, t));
        yield return null;
    }

    var(zz);
}
或:


要在LINQPad/unity中编译的存根方法:

public class Mathf { public static float SmoothStep(float aa, float zz, float t) => 0; }
public class Time { public static float time => DateTime.Now.Ticks; }
public class Vector3 { public static Vector3 Lerp(Vector3 aa, Vector3 zz, float t) => null; }

我喜欢Tweeng,但是如果协同程序只能用于单行为,为什么要扩展float呢?你应该为单行为做扩展,例如,我做了一个扩展来做插值:

public static void _Interpolate(this MonoBehaviour monoBehaviour, float duration,
    Action<float, bool> callback, float from, float to, Interpolator interpolator)
{
    monoBehaviour.StartCoroutine(ExecuteInterpolation(interpolator, duration, callback, from, to));
}
public static void\u插值(此单一行为、浮动持续时间、,
动作回调、浮点自、浮点至、插值器(插值器)
{
start例程(ExecuteInterpolation(插值器、持续时间、回调、from、to));
}
所以我只是在扩展中启动了一个协同程序:

private static IEnumerator ExecuteInterpolation(Interpolator interpolator, float duration,
    Action<float, bool> callback, float from, float to)
{
    float sT = Time.time;
    float eT = sT + duration;
    bool hasFinished = false;
    while (Time.time < eT)
    {
        float t = (Time.time - sT) / duration;
// ----> my logic here with callback(to, false)
        yield return null;
    }

    hasFinished = true;
    callback(to, hasFinished);
}
专用静态IEnumerator ExecuteInterpolation(插值器插值器,浮点持续时间,
动作回调、浮点从、浮点到)
{
float sT=Time.Time;
浮动eT=sT+持续时间;
bool hasFinished=false;
while(Time.Time我在这里的逻辑与回调(to,false)
收益返回空;
}
hassfinished=true;
回调(到,已完成);
}

请注意,我有一个布尔值来表示插值已完成,之所以发生这种情况,是因为依赖浮点比较来检查流的结束不是最佳做法,如果它在最后一次交互之前对结果进行最大结果取整,我们将对最后一次交互进行两次回调。

是的,您可以添加一个通用参数
T
float
/
Vector3
),然后以
Lerp/SmoothStep
的形式传入
Func
啊,基本上是添加了另一个参数。如果让扩展能够解决这个问题,那就太好了,我想可以将这个除法下传给另一个泛型function@JoeBlow您可以通过执行
if(typeof(T)来打开类型==typeof(float))…
(我很抱歉上面代码中的错误,现在已修复)。您当然可以在循环中执行此操作,但在每次迭代中都必须做出相同的决定。预先存储
Func
可以让您执行
if
一次,然后在每次迭代中重用结果。对,但我的意思是,可以将
MakeTransform
中的代码简单地放入
Tweeng
(当然,在顶部,以避免每次循环)…我会尝试它!@JoeBlow绝对,人们可以在
Tweeng
中内联该代码。我将其分离出来,因为对我来说
typeof(T)
的条件有点“不干净”,而剩下的
Tweeng
很好,很干净。@JoeBlow请用上一次编辑的显式转换来尝试修复。@JoeBlow编辑应该可以工作,或者至少现在可以编译了。嘿,Fernando!当然,你可以根据自己的喜好“重新创建”任何扩展,它只是语法糖果-它没有实际意义。实际上,“Tweeng”的使用非常广泛。(例如)因为这是一个动画,所以(对我来说)这是一个“大约”的时间,所以这是逻辑上的“基础”语法。正如你提到的,它只能用在单一行为中-很自然,这对统一中的许多/大多数事情都是如此。实际上,它只是一种惯例,让它在几秒钟内消失。如果你愿意,你当然可以用不同的顺序进行辩论。享受吧!嗨,Fattie,“Tweeng”它本身是一个非常有用的想法,我的代码只不过是一个用于MonoBehavior而不是float的Tweeng,我可以用MonoB重构Tweeng。尽管如此,不仅仅是语法不好放。75.Tweeng(params[]),但一旦操作只能执行,它就不正确了
public static IEnumerator Tweeng(this float duration, System.Action<float> var, float aa, float zz)
{
    return Tweeng(duration, var, aa, zz, Mathf.SmoothStep);
}
public static IEnumerator Tweeng(this float duration, System.Action<Vector3> var, Vector3 aa, Vector3 zz)
{
    return Tweeng(duration, var, aa, zz, Vector3.Lerp);
}

private static IEnumerator Tweeng<T>(this float duration,
         System.Action<T> var, T aa, T zz, Func<T,T,float,T> thing)
{
    float sT = Time.time;
    float eT = sT + duration;

    while (Time.time < eT)
    {
        float t = (Time.time - sT) / duration;
        var(thing(aa, zz, t));
        yield return null;
    }

    var(zz);
}
float a = 5;
float b = 0;
float c = 0;
a.Tweeng(q => {}, b, c);
float a = 0;
Vector3 b = null;
Vector3 c = null;
a.Tweeng(q => {}, b, c);
public class Mathf { public static float SmoothStep(float aa, float zz, float t) => 0; }
public class Time { public static float time => DateTime.Now.Ticks; }
public class Vector3 { public static Vector3 Lerp(Vector3 aa, Vector3 zz, float t) => null; }
public static void _Interpolate(this MonoBehaviour monoBehaviour, float duration,
    Action<float, bool> callback, float from, float to, Interpolator interpolator)
{
    monoBehaviour.StartCoroutine(ExecuteInterpolation(interpolator, duration, callback, from, to));
}
private static IEnumerator ExecuteInterpolation(Interpolator interpolator, float duration,
    Action<float, bool> callback, float from, float to)
{
    float sT = Time.time;
    float eT = sT + duration;
    bool hasFinished = false;
    while (Time.time < eT)
    {
        float t = (Time.time - sT) / duration;
// ----> my logic here with callback(to, false)
        yield return null;
    }

    hasFinished = true;
    callback(to, hasFinished);
}