简体   繁体   中英

C# Generic Functions

Seeking some help on C# generics. I am working in Unity3D and am rolling a BiLerp function as Unity3D doesn't have one.

public Vector3 BiLerp(Vector2 _uv, Vector3 _00, Vector3 _01, Vector3 _10, Vector3 _11)
{
    return _00 * (1 - _uv.x) * (1 - _uv.y) +
           _10 * _uv.x * (1 - _uv.y) +
           _01 * _uv.y * (1 - _uv.x) +
           _11 * _uv.x * _uv.y;
}

However, I would like to make this function a little more robust.

  1. I would like to make it generic so that it takes in any type which can be multiplied by a float
  2. I am unsure as to whether or not I should make this static. I am assuming that as it does not use any member variable then yes. Should the class that this is stored in also be static, the class will just be for math helpers omitted by unity (Matrix2x2) etc.
  3. How does C# const work in this instance?
  4. In C++ I would pass the parameters by reference. II correct in assuming that C# is already doing this? and that the ref keyword is some other dark magic tool?

If there is any other suggestions then please feel free. I have only been working in C# for 6 weeks now and could use any suggestions.

  1. Although it's possible to make this work by passing in a delegate that does the multiplication, it will be a lot slower. I actually think you'd be better off writing multiple overloads instead.

  2. Yes you should, and you should also put it into a static class. (IMHO!) I was going to suggest that you make it an extension method , but on reflection it has too many parameters to make it that useful.

  3. C# consts are similar to C++ consts, but the general consensus is that they should only be private (or possibly internal).

  4. Actually, Vector2 and Vector3 are structs so they are passed by value. If you want to pass them by reference, use the ref keyword:

     public Vector3 BiLerp( ref Vector2 _uv, ref Vector3 _00, ref Vector3 _01, ref Vector3 _10, ref Vector3 _11)` 

However, there are only two reasons to do so (for structs):

  1. Because you want to change the original value being passed in.

  2. To speed it up by only passing a reference (ie pointer in C++ terms).

The first doesn't apply in your code, and the second seems pointless for such small structs (in fact, all structs should be small, so it almost never applies for well-designed structs).

I would like to make it generic so that it takes in any type which can be multiplied by a float

Unfortunately C#'s generic type system does not support this kind of constraint. This is a fairly frequently requested feature that the C# team has considered, but it would require a lot of work in the underlying CLR type system. There is a chance that it will be implemented in the future, but I wouldn't hold my breath waiting for that day if I were you.

I am unsure as to whether or not I should make this static. I am assuming that as it does not use any member variable then yes.

Yes, make it static.

Should the class that this is stored in also be static, the class will just be for math helpers.

Yes.

How does C# const work in this instance?

C# const is different than C++ const; it is much simpler. In C# a const field or local is simply a name for a compile time constant number or string, end of story. (OK, you can also have a const of reference type but it must be null, so that's not that interesting.) There's none of this "here's a reference but you can't call any methods that mutate it" rules that you see in C#.

The best practice is to make all value types immutable in the first place, so C++-style const is not really necessary.

Marking a field "readonly" makes it so that it can only be changed in the constructor.

In C++ I would pass the parameters by reference. Am I correct in assuming that C# is already doing this?

No. Value types are passed by value.

the ref keyword is some other dark magic tool?

The ref keyword is just like C++ references: it makes one variable an alias for another . You would normally only use in C# for situations where you wanted to mutate a variable supplied by the caller. As I said before, C# does not have the C++ concept of a "const reference", but since value types in C# are supposed to be small, and therefore efficient to pass by value, you generally don't need the concept of "const reference" to say "I want to pass this by reference for performance but not actually mutate the variable".

1) I would like to template it so that it takes in any type which can be multiplied by a float

Not sure if that is possible with the current implementation of generics in C#. You are not able to define a T where T : float . The compiler will tell you that only class or interface could be specified as constraint .

2) I am unsure as to whether or not I should make this static. ... Should the class that this is stored in also be static

I'd not make a class static because you have 1 static method in it. I don't see a problem in the method you defined. Making it static since it does not use members makes sense (looks like a helper method). You could also make it a extension method as suggested in Matthews answer. Something like:

public static class Vector2Ext
{
    public static Vector3 BiLerp(
        this Vector2 _uv,
        Vector3 _00,
        Vector3 _01,
        Vector3 _10,
        Vector3 _11)
    {
        // your implementation
    }
}

That way you could call the method BiLerp as a method on Vector2.

Vector2 vector2 = ...;
vector2.BiLerp(_00, _01, _10, _11);

If it makes sense to design it in that fashion you probably can judge best in this case.

3) How does C# const work in this instance?

A bit vague, not sure what you mean. Does MSDN help here?

4) In C++ I would pass the parameters by reference. II correct in assuming that C# is already doing this? and that the ref keyword is some other dark magic tool?

That's a topic on itself. If you use the ref keyword then you pass the type as a reference. It makes sense if VectorXD are immutable types. You want to pass them by ref if you need the value of the valuetype back in the calling side. Looking at your code, I interpret it as you pass a few values, use them to calculate a Vector3D and return that. I don't see the need for ref here. But maybe I again misunderstand your question. Maybe MSDN helps to understand the use for ref .

C# does not have templates, as they are known in C++. The term is generics and they are a little more constrained than templates in C++ code. For what you require, it is impossible to inherit from float type, neither it is possible to put a generic constraint to a numeric type, since float is a ValueType . Value types in C# (and .NET in general) cannot be extended by type inheritence.

As a suggestion, you may use float or double directly. C# performs automatic casts to float and double from all other numeric types (maybe except decimal ).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM