The short answer is no. C# isn't "snakey" enough for that. That was a feature of Python that I always liked. I wish more languages had it, but C# doesn't. Not directly anyway.
Of course, there are plenty of ways to get multiple things back from a method. Let me enumerate them:
1. Return an Array
This would look like this:
double[] FindTrajectory()
{
return new double[] { a, p };
}
Then:
double[] results = FindTrajectory();
double angle = results[0];
double power = results[1];
This is probably the simplest of approaches, but it has two serious drawbacks:
- It works best if all of the return values are of the same type, otherwise you have to use an array of type object and perform a bunch of casting.
- You have to manually pack and unpack the array, which means there's the potential for error. ("Was power first or second?" etc.)
2. Create an Object to Store Them All
public class Trajectory
{
public double Angle { get; private set; }
public double Power { get; private set; }
public Trajectory(double angle, double power)
{
Angle = angle;
Power = power;
}
}
(And actually, looking back at it, that is a perfect time for a struct instead of a class. Either one will work, functionally.)
Then:
public Trajectory GetTrajectory()
{
return new Trajectory(a, p);
}
Trajectory trajectory = GetTrajectory();
That is a more "object-oriented" approach. It solves some of the problems that the first thing had. Your types can be different, and because the properties that the data is stored in are named ("Angle" and "Power") is is unlikely that anyone would mess it up.
But on the other hand, it means building a full class for use in potentially one location. Which if that's the case, seems like overkill for sure. (If you're using this data all over the place, this is probably what I'd recommend.)
3. Use the Generic Tuple Class
If you like the above approach, but you don't like building a whole new class for a single use, you might consider using the Tuple class. It's generic, so you have to understand C# generics for it to be useful. I don't know what level you see yourself at, but generics aren't exactly a beginner level feature. I'm not going to explain generics here, but see that link for more information.
This would look more like this:
public Tuple<double, double> GetTrajectory()
{
return new Tuple<double, double>(a, p);
}
Tuple<double, double> trajectory = GetTrajectory();
double angle = trajectory.Item1;
double power = trajectory.Item2;
The Tuple class lets you package up multiple values to pass around. Because it's generic, you could create one that has any parameter types. This keeps your type safety, so you know what type of data you're working with at all times, and you don't have to build and maintain a new class on your own, but Item1 and Item2 are terrible names. They're completely meaningless. If you built your own class, that's not a problem.
Again, I'd only recommend doing this if you are only going to use this in one place. (Even then, I'd personally still give strong consideration to option #2.)
4. Use Output Parameters
The fourth option is to use output parameters. This, again, isn't exactly C# 101. The method would be restructured to look like this:
public static void GetTrajectory(out double angle, out double power)
{
angle = a;
power = p;
}
And then you'd call it like this:
double angle;
double power;
GetTrajectory(out angle, out power);
Using output parameters means that the two methods are essentially sharing the same memory location, and can both read from it and write to it. With the out keyword, we establish the expectation that the called method will write to the location before it finishes. (If you don't, it won't compile.)
Output parameters can be very useful, and very powerful. This exact situation is a big part of why they exist. But it takes a little bit of getting used to. Having two methods share the exact same memory/storage location like this has some gotchas that take some experience to get used to. Output parameters often are overused when people first learn about them. (Don't go make every method use output parameters.)
For the sake of being complete (I've typed all this already; I might as well keep going, right?) I should also mention that you can also have reference parameters, which look the same, but use the ref keyword instead of out. These, too, share the same storage location in the calling site and the called method. However, ref established the expectation that the caller will be the one to make sure it's assigned. The called method can assume there's already some data there to work with.
Whew. That was a lot. Hopefully I've helped you, not confused you. My personal normal approach is to build a class or struct for it (Option #2). But there is a time and a place for all of the above. You just have to consider the pros and cons of each, and what you're hoping to achieve.
Let me know if you have other questions from what I said…