Can operations be generalized?
I just wrote this code:
private double PerformOperation(OperationEnum operation,开发者_高级运维 double aggregateValue,
double sourceValue)
{
if (operation == OperationEnum.Sum)
return aggregateValue + sourceValue;
if (operation == OperationEnum.Subtract)
return aggregateValue - sourceValue;
if (operation == OperationEnum.Multiply)
return aggregateValue * sourceValue;
if (operation == OperationEnum.Divide)
return aggregateValue / sourceValue;
throw new InvalidOperationException("Unsupported Aggregation Operation");
}
It seems very repetitive. Is there a way to generalize this? So I don't have to have 4 lines that are the same except a different sign?
(Note: if there is a better way that does not use the OperationEnum
that is great)
You can make a Dictionary<OperationEnum, Func<double, double, double>>
:
static readonly Dictionary<OperationEnum, Func<double, double, double>> operations =
new Dictionary<OperationEnum, Func<double, double, double>> {
{ OperationEnum.Sum, (a, b) => a + b },
...
};
It looks about right to me, although I'd use a switch
statement for this. But maybe I don't understand what you're trying to do?
switch(operation)
{
case OperationEnum.Sum: return aggregateValue + sourceValue;
case OperationEnum.Subtract: return aggregateValue - sourceValue;
case OperationEnum.Multiply: return aggregateValue * sourceValue;
case OperationEnum.Divide: return aggregateValue / sourceValue;
default:
throw new InvalidOperationException("Unsupported Aggregation Operation");
}
It's essentially the same, but at least it looks prettier.
You can create a dictionary of delegates, so your function will look something like:
private double PerformOperation(OperationEnum operation, double aggregateValue,
double sourceValue)
{
return operators[operation](aggregateValue, sourceValue);
}
Yes, using List<Func<double, double, double>>
:
List<T>
accessor works mush faster than Dictionary<> accessor, and comparable to switch statement ;)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace test
{
class Program
{
enum OperationEnum : int { Sum, Muiltiply, Divide, Subtract }
static List<Func<double, double, double>> actions = new List<Func<double, double, double>>()
{
{ (a,b) => a+b },
{ (a,b) => a*b },
{ (a,b) => a/b },
{ (a,b) => a-b },
};
static void Main(string[] args)
{
Console.WriteLine(string.Format("{0}", actions[(int)OperationEnum.Sum](1, 3));
}
}
}
Nope... it's not quite that generalizable, although I wish it was too. :\
A switch would be prettier at least :) and the code will be more efficient (array look-ups etc.). Furthermore, the compiler and IDE can give you some hints when you miss certain options etc.
But as stated in my comment, this isn't really an answer just general code improving.
switch (operation)
{
case OperationEnum.Sum:
return aggregateValue + sourceValue;
case OperationEnum.Subtract:
return aggregateValue - sourceValue;
case OperationEnum.Multiply:
return aggregateValue * sourceValue;
case OperationEnum.Divide:
return aggregateValue / sourceValue;
default:
throw new InvalidOperationException("Unsupported Aggregation Operation");
}
This should do it, however, I believe a switch statement would be the more efficient.
private double Evaluate(string expression)
{
return (double)new System.Xml.XPath.XPathDocument
(new System.IO.StringReader("<r/>")).CreateNavigator().Evaluate
(string.Format("number({0})", new
System.Text.RegularExpressions.Regex(@"([\+\-\*])")
.Replace(expression, " ${1} ")
.Replace("/", " div ").Replace("%", " mod ")));
}
OR
private double Evaluate(string expression)
{
System.Data.DataTable table = new System.Data.DataTable();
table.Columns.Add("expression", string.Empty.GetType(), expression);
System.Data.DataRow row = table.NewRow();
table.Rows.Add(row);
return double.Parse((string)row["expression"]);
}
Then...
public double PerformOperation(double x, double y, string op)
{
string exp = string.Format("{0} {1} {2}"
, x.ToString()
, op, y.ToString());
return Evaluate(exp);
}
I'm not sure of the context of this, but rather than the enum you could use a delegate that performs the desired operation to be passed into your "PerformOperation"-method. However you probably don't even need that static method if you would use this approach. Another benefit is that you don't have to care about the special case where the operation is not supported, any operation is supported. Here's a quick example:
namespace Example
{
using System;
public delegate double Operation(double first, double second);
public static class Operations
{
public static readonly Operation Sum = (first, second) => first + second;
public static readonly Operation Subtract = (first, second) => first - second;
public static readonly Operation Multiply = (first, second) => first * second;
public static readonly Operation Divide = (first, second) => first / second;
}
class Program
{
static void Main(string[] args)
{
double seed = 0;
double aggregateValue = 0;
aggregateValue = PerformOperation(Operations.Sum, 5, 10);
Console.WriteLine(aggregateValue);
aggregateValue = PerformOperation(Operations.Multiply, aggregateValue, 10);
Console.WriteLine(aggregateValue);
aggregateValue = PerformOperation(Operations.Subtract, aggregateValue, 10);
Console.WriteLine(aggregateValue);
aggregateValue = PerformOperation(Operations.Divide, aggregateValue, 10);
Console.WriteLine(aggregateValue);
// You can even pass delegates to other methods with matching signatures,
// here to get the power of ten.
aggregateValue = PerformOperation(Math.Pow, aggregateValue, 10);
Console.WriteLine(aggregateValue);
Console.ReadLine();
}
private static double PerformOperation(Operation operation, double aggregateValue, double sourceValue)
{
return operation(aggregateValue, sourceValue);
}
}
}
Using this approach you can easily extend your program with new operations without even touching the PerformOperation-method. This can be taken quite a few steps further but without knowing the context it's hard to describe.
精彩评论