- Home /
Accept multiple types via implicit operator as method argument
I'm having an issue with some C# theory. Basically, I want to take the rolling average of a list of Vector3s or a list of a custom struct, MovePoint, which is just a Vector3 and a float indicating the time delta from the previous point. I have the implicit operator defined below:
public static implicit operator Vector3(MovePoint mp) {
return mp.pos;
}
The issue here is code elegance and compactness. My rolling average function looks like this:
protected Vector3 CalculateRollingAverage(List<Vector3> moveList, int numSamples = 3) {
int endSample = moveList.Count;
int startSample = Mathf.Max(0, endSample - numSamples);
Vector3 ret = new Vector3();
for (int i = startSample; i < endSample; ++i) {
ret += moveList[i];
}
ret /= numSamples;
return ret;
}
The issue is that C# won't take an implicit conversion. I can copy and paste the code, change List Vector3
to List MovePoint
to overload it, and be good to go, but obviously if I refactor my function I have to do it twice, and copy and pasting is a bad habit to get into. It's also a lot less practical if the function was larger. Performance is a concern, so writing some sort of conversion function that returns a new list is out of the question.
I'm just wondering if I'm missing something and the answer is much simpler. A generic solution won't work because Vector3 is a struct, so you can't cast to it.
Implicit operator works as expected here. The problem is that it is defined to convert $$anonymous$$ovePoint to Vector3, not List<$$anonymous$$ovePoint>to List<Vector3>
Answer by Azrapse · Jan 21, 2014 at 09:02 AM
I don't think generics take account on the implicit operator
s you have defined, so the method won't accept a List< MovePoint >
where it expects a List< Vector3 >
. It only works with some kind of inheritance.
The only thing I can think of right now that wouldn't involve implementing an interface common for both Vector3
and MovePoint
is to use a projecting lambda and pass it as parameter to the method.
protected Vector3 CalculateRollingAverage<T>(List<T> moveList, Func<T, Vector3> select, int numSamples = 3)
{
int endSample = moveList.Count;
int startSample = Mathf.Max(0, endSample - numSamples);
Vector3 ret = new Vector3();
for (int i = startSample; i < endSample; ++i) {
ret += select(moveList[i]);
}
ret /= numSamples;
return ret;
}
Then, when you call that method passing a List< Vector3 >
you call it like this:
var rollingAverage = CalculateRollingAverage(vectorList, v => v, 3);
and when you call it passing a List< MovePoint >
, you call it like:
var rollingAverage = CalculateRollingAverage(movePointList, mp => mp.pos, 3);
I cannot see why would this be any less efficient than the implicit
conversion (it's just a call to a method in both examples). And this lets you use other structs or classes with that method as long as you supply a proper selecting lambda for them.
Vector3 is a struct defined in UnityEngine.dll. You can't change it, so that it implements an interface.
Oops. That was a typo. I mean 'wouldn't' and I typed 'would'. Thanks for pointing it out! :)
Thanks, that works. Actually I can call the function the same regardless if its a list of $$anonymous$$ovePoints or list of Vector3 due to the implicit conversion, using the x => x lambda. Is there a way to set a default value for select?
You can add a new method overload for this. But out of curiosity - how do you want to set a default, if you don't know the type?
Your answer
Follow this Question
Related Questions
Implicit type GetComponent call 0 Answers
Does Android support generics? 1 Answer
C# Generics not constraining correctly? 1 Answer
GetComponent generic type 0 Answers
How to serialize a concrete derived class from generic ScriptableObject base 1 Answer