6

我想知道在 C# 中是否有一种方法可以拥有基于原始类型的类型,并将其复制以使用其他原始类型。

我知道这不是很清楚,我真的不知道如何解释这个(英语不是我的母语,对不起......),所以我会尝试使用伪代码来解释它。

一个简单的例子:

public struct Vector2d {
    public double X;
    public double Y;

    //Arithmetic methods: Length, normalize, rotate, operators overloads, etc...
}

问题是我想要这种类型的 float 和 int32 版本。

我实际上在做什么(有效的 C# 代码):

//This type contains all useful methods
public struct Vector2d {
    public float X;
    public float Y;

    public Vector2f AsFloat() {
        return new Vector2f((float)X, (float)Y);
    }
    public Vector2f AsInteger() {
        return new Vector2i((int)X, (int)Y);
    }

    //Arithmetic methods
}

//These types are only here to be casted from/to, all the arithmetics methods are on the double-based type
public struct Vector2f {
    public float X;
    public float Y;

    public Vector2f AsDouble() {
        return new Vector2d(X, Y);
    }
    public Vector2f AsInteger() {
        return new Vector2i((int)X, (int)Y);
    }
}
public struct Vector2i {
    public int X;
    public int Y;

    public Vector2f AsFloat() {
        return new Vector2f(X, Y);
    }
    public Vector2f AsDouble() {
        return new Vector2d(X, Y);
    }
}

它有效,但并不“性感”,并且在使用 AsXXX 方法进行大量演员表的情况下,不可避免地会对表演产生影响。

理想情况下,我会对所有三种类型都有算术方法,但维护起来会很痛苦......

什么是理想的解决方案(伪代码,无效的 C#):

public struct Vector2<T> where T : numeric {
    public T X;
    public T Y;

    public T Length {
        return (T)Math.Sqrt(X * X + Y * Y);
    }
    //Other arithmetic methods
}

我知道目前在 C# 中这是不可能的,但这是真正的问题:

您对如何妥善有效地处理此问题有任何想法吗?

我一直在想的(伪代码,无效的 C#):

//The TYPE defined constant should be used by Vector2Body instead of plain typed "double", "float", etc...

public struct Vector2d {
    #define TYPE double
    #import Vector2Body
}

public struct Vector2f {
    #define TYPE float
    #import Vector2Body
}

public struct Vector2i {
    #define TYPE int
    #import Vector2Body
}

这样,我不会有重复的代码,更容易维护

等待你的想法:)

PS:如果版主对如何更好地格式化我的问题有想法,请随时编辑它:)

4

3 回答 3

5

这是@mike-z给出的一个非常好的方法,使用 T4 模板:

模板(.tt 文件):

<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".cs" #>
using System;

namespace My.Math {
<# Vector2Body("d", "double"); #>
<# Vector2Body("f", "float"); #>
<# Vector2Body("i", "int"); #>
}

<#+ private void Vector2Body(string suffix, string t) { #>

    public struct Vector2<#= suffix #> {
        public <#= t #> X;
        public <#= t #> Y;

        //Arithmetic for <#= t #>...
    }

<#+ } #>

以及自动生成的代码:

using System;

namespace My.Math {

    public struct Vector2d {
        public double X;
        public double Y;

        //Arithmetic for double...
    }


    public struct Vector2f {
        public float X;
        public float Y;

        //Arithmetic for float...
    }


    public struct Vector2i {
        public int X;
        public int Y;

        //Arithmetic for int...
    }

}

没有通用,所以没有性能影响,代码编写一次......

于 2013-06-10T10:03:02.823 回答
4

你可以做类似的事情,

public struct Vector2<T> where T : IConvertible
{
    private readonly double x;
    private readonly double y;

    public Vector2(T x, T y)
    {
        this.x = x.ToDouble(CultureInfo.CurrentCulture);
        this.y = y.ToDouble(CultureInfo.CurrentCulture);
    }

    public T X
    {
        get
        {
            return ConvertBack(this.x);
        }
    }

    public T Y
    {
        get
        {
            return ConvertBack(this.y);
        }
    }

    private static T ConvertBack(double d)
    {
        return (t)Convert.ChangeType(d, typeof(T), CultureInfo.CurrentCulture); 
    }
}

但是,如果您不想要通用治疗。那么你还不如有几个专门的Vector2类型。

于 2013-06-10T09:57:26.707 回答
0

我想到了与 Jodrell 建议的相同的解决方案。只想补充:

private Vector2(double x, double y)
{
 this.x = x;
 this.y = y;
}

public Vector2<E> ToVector<E>() where E : IConvertible
{
 return  new Vector2<E>(x, y);
}
于 2013-06-10T13:59:52.677 回答