Factory method by type name - c#

I need to create factory method that takes type name and params. Example:
ShapeFactory.CreateShape("Circle", new Object[] { 4 }) ShapeFactory.CreateShape("Rectangle", new Object[] { 3, 5 })
All shapes derived from BaseShape with method .GetName(); I cannot put together, how to use GetName method to get shape name and create it by string parameter.
Factory method interface:
public static object CreateShape(string shape, object[] parameters)
{
// realization for example
switch (shape)
{
case "Rectangle":
// if (parameters.Length != 2) throw new WrongParamCountException();
return new Rectangle(TryCastToFloat(parameters[0]), TryCastToFloat(parameters[1]));
case "Circle":
// if (parameters.Length != 1) throw new WrongParamCountException();
return new Circle(TryCastToFloat(parameters[0]));
case "Square":
// if (parameters.Length != 1) throw new WrongParamCountException();
return new Square(TryCastToFloat(parameters[0]));
default:
throw new UnsupportedShapeException();
}
}

You will not be able to construct the object the way you want. If all you have is a string value at run time, a switch statement like this is probably (unfortunately) your best option. But we can improve it somewhat:
public static BaseShape CreateShape(string shape, params float[] parameters)
{
switch (shape)
{
case "Rectangle":
// if (parameters.Length != 2) throw new WrongParamCountException();
return new Rectangle(parameters[0], parameters[1]);
break;
case "Circle":
// if (parameters.Length != 1) throw new WrongParamCountException();
return new Circle(parameters[0]);
break;
case "Square":
// if (parameters.Length != 1) throw new WrongParamCountException();
return new Square(parameters[0]);
break;
default:
throw new UnsupportedShapeException();
}
}
Now, the result of method will be typed to use the BaseShape, which is an improvement over Object. Additionally, we're forcing the caller to ensure their arguments will cast to float. Finally, we no longer need to construct an array manually. You can instead call the method like this:
var circle = ShapeFactory.CreateShape("Circle", 2.0);
var rect = ShapeFactory.CreateShape("Rectangle", 3.0, 5.0);
We could also try generics to get even better typing:
public static T CreateShape<T>(string shape, params float[] parameters) where T : BaseShape
{
switch (shape)
{
case "Rectangle":
// if (parameters.Length != 2) throw new WrongParamCountException();
return new Rectangle(parameters[0], parameters[1]);
break;
case "Circle":
// if (parameters.Length != 1) throw new WrongParamCountException();
return new Circle(parameters[0]);
break;
case "Square":
// if (parameters.Length != 1) throw new WrongParamCountException();
return new Square(parameters[0]);
break;
default:
throw new UnsupportedShapeException();
}
}
The implementation is the same, but now you must also specify the shape as a type argument when calling:
var circle = ShapeFactory.CreateShape<Circle>("Circle", 2.0);
The advantage here is the resulting circle variable really is typed as a Circle. The downside is you have to know how call the method at compile time, rather than, say, just loading the shape string from a database column at run time.

Assuming GetName is an instance property, you can collect the sub-types of BaseShape and map them to their GetName but this requires a public constructor that takes no parameters.
public static class ShapeFactory {
static Dictionary<string,Type> shapeTypeMap = Assembly.GetExecutingAssembly()
.GetTypes()
.Where(t => t.IsSubclassOf(typeof(BaseShape)))
.ToDictionary(t => ((BaseShape)Activator.CreateInstance(t)).GetName, t => t);
public static object CreateShape(string shape, params object[] parameters) {
if (shapeTypeMap.TryGetValue(shape, out var shapeType))
return Activator.CreateInstance(shapeType, parameters);
else
throw new UnsupportedShapeException();
}
}
This is not recommended.

Related

A list of unique sequences with EqualityComparer

I want to make a List<List<int>> structure so that only distinct sequences of numbers can be added. For this I create an EqualityComparer this way:
public class ListEqualityComparer<TElement> : EqualityComparer<List<TElement>>
{
Object hashHelp1 = new Object();
Object hashHelp2 = new Object();
public override bool Equals(List<TElement> x, List<TElement> y)
{
if (x == null && y == null)
return true;
else if (x == null || y == null)
return false;
else if (x.SequenceEqual(y))
return true;
else
return false;
}
public override int GetHashCode(List<TElement> obj)
{
return (hashHelp1, hashHelp2).GetHashCode();
}
}
so I want two lists to be considered equal, if their sequences of elements are equal.
However, if I try to create
ListEqualityComparer<List<int>> LEC = new ListEqualityComparer<List<int>>();
List<List<int>> list = new List<List<int>>(LEC);
I get an error:
Argument 1: cannot convert from 'MyNamespace.MyFolder.ListEqualityComparer<System.Collections.Generic.List<int>>' to 'System.Collections.Generic.IEnumerable<System.Collections.Generic.List<int>>'.
What does it actually mean?
On my belief the program should just replace TElement with List<int>and go, but obviously something different happens here. I am somehow confused, because I have implemented abother EqualityComparer recently, and the lines
MyStructureEqualityComparer<int, ulong> MSEC= new MyStructureEqualityComparer<int, ulong>();
HashSet<MyStructure<int, ulong>> test = new HashSet<MyStructure<int,ulong>>(MSEC);
were fine. What I am doing wrong?

Add range dynamically to list

I have a List<byte> that stores the value of a variable byte by byte. I am trying to build up this variable by respect to its original data type.
Example of the result:
List<byte> varBytes = new List<byte>();
varBytes.Add(0x12);
varBytes.Add(0x34);
varBytes.Add(0x56);
varBytes.Add(0x78);
//After the conversion of UInt32:
varReady = 0x78563412;
Here is a snippet of my class that returns the value of the variable.
public static object GetTypedString(List<byte> varBytes, string varType)
{
object varReady;
switch (varType)
{
case "uint16":
UInt16 varReady = BitConverter.ToUInt16(varBytes.ToArray<byte>(), 0);
break;
case "uint32":
UInt32 varReady = BitConverter.ToUInt32(varBytes.ToArray<byte>(), 0);
break;
//repeat case for each data type
}
return varReady ;
}
The problem comes up if my variable is only 2 bytes long and if I want to show that variable as UInt32. The BitConverter.ToUInt32 will throw this exception:
Destination array is not long enough to copy all the items in the collection.
Because the varBytes list only has 2 bytes but BitConverter.ToUInt32 is trying to read 4 bytes. My solution was to add dummy bytes to the end of the list in this case:
.
.
.
case "uint32":
int difference = sizeof(UInt32) - varSize; //we know the variable size already
if(difference > 0)
{
varToDisp.value.AddRange(new byte[difference]);
}
UInt32 varReady = BitConverter.ToUInt32(varBytes.ToArray<byte>(), 0);
break;
.
.
.
This works but didn't seem a good way to me since it will edit the original List and consumes some time. Is there any easier way to achieve this?
You can create the array (not list) with required Length with a help of Linq Concat; I suggest routine redesign as well.
Code:
// Let's implement a generic method: we want, say, uint not object from given list
public static T GetTypedString<T>(List<byte> varBytes) where T: struct {
if (null == varBytes)
throw new ArgumentNullException(nameof(varBytes));
// sizeof alternative
// char is Ascii by default when marshalling; that's why Marshal.SizeOf returns 1
int size = typeof(T) == typeof(char)
? sizeof(char)
: System.Runtime.InteropServices.Marshal.SizeOf(typeof(T));
// if data is too short we should pad it; either from left or from right:
// {0, ..., 0} + data or data + {0, ..., 0}
// to choose the way, let's have a look at endiness
byte[] data = (size >= varBytes.Count)
? BitConverter.IsLittleEndian
? varBytes.Concat(new byte[size - varBytes.Count]).ToArray()
: new byte[size - varBytes.Count].Concat(varBytes).ToArray()
: varBytes.ToArray();
// A bit of reflection: let's find out suitable Converter method
var mi = typeof(BitConverter).GetMethod($"To{typeof(T).Name}");
if (null == mi)
throw new InvalidOperationException($"Type {typeof(T).Name} can't be converted");
else
return (T)(mi.Invoke(null, new object[] { data, 0 })); // or data.Length - size
}
Then you can use it as follow:
List<byte> varBytes = new List<byte>();
varBytes.Add(0x12);
varBytes.Add(0x34);
varBytes.Add(0x56);
varBytes.Add(0x78);
int result1 = GetTypedString<int>(varBytes);
long result2 = GetTypedString<long>(varBytes);
Console.WriteLine(result1.ToString("x"));
Console.WriteLine(result2.ToString("x"));
// How fast it is (Linq and Reflection?)
var sw = new System.Diagnostics.Stopwatch();
int n = 10000000;
sw.Start();
for (int i = 0; i < n; ++i) {
// The worst case:
// 1. We should expand the array
// 2. The output is the longest one
long result = GetTypedString<long>(varBytes);
//Trick: Do not let the compiler optimize the loop
if (result < 0)
break;
}
sw.Stop();
Console.WriteLine($"Microseconds per operation: {(sw.Elapsed.TotalSeconds/n*1000000)}");
Outcome:
78563412
78563412
Microseconds per operation: 0.84716933
Edit: If you insist on type name (string varType) instead of generic parameter <T> first of all let's extract a model (type name - type correspondense):
private static Dictionary<string, Type> s_Types =
new Dictionary<string, Type>(StringComparer.OrdinalIgnoreCase) {
{ "uint16", typeof(UInt16)},
{ "ushort", typeof(UInt16)}, // <- you can add synonyms if you want
{ "int", typeof(Int32)},
{ "int32", typeof(Int32)},
{ "long", typeof(Int64)},
{ "int64", typeof(Int64)},
//TODO: add all the other names and correspondent types
};
Then you can implement it as
public static object GetTypedString(List<byte> varBytes, string varType) {
if (null == varBytes)
throw new ArgumentNullException(nameof(varBytes));
else if (null == varType)
throw new ArgumentNullException(nameof(varType));
Type type = null;
if (!s_Types.TryGetValue(varType, out type))
throw new ArgumentException(
$"Type name {varType} is not a valid type name.",
nameof(varBytes));
// sizeof alternative
// char is Ascii by default when marshalling; that's why Marshal.SizeOf returns 1
int size = typeof(T) == typeof(char)
? sizeof(char)
: System.Runtime.InteropServices.Marshal.SizeOf(typeof(T));
byte[] data = (size >= varBytes.Count)
? BitConverter.IsLittleEndian
? varBytes.Concat(new byte[size - varBytes.Count]).ToArray()
: new byte[size - varBytes.Count].Concat(varBytes).ToArray()
: varBytes.ToArray();
var mi = typeof(BitConverter).GetMethod($"To{type.Name}");
if (null == mi)
throw new InvalidOperationException(
$"Type {type.Name} (name: {varType}) can't be converted");
else
return mi.Invoke(null, new object[] { data, 0 }); // data.Length - size
}
Demo:
string result1 = (GetTypedString(varBytes, "Int64") as IFormattable).ToString("x8", null);
Rather than using .ToArray you could preallocate your array to the correct size and use .CopyTo.
Example:
var byteArray = new byte[sizeof(UInt32)];
varBytes.CopyTo(byteArray);
UInt32 varReady = BitConverter.ToUInt32(byteArray, 0);
You can check for the length of the array and convert it to smaller types then cast the required one
case "uint32":
{
if (varBytes.Count == 1)
{
varReady = (UInt32)varBytes[0];
}
else if (varBytes.Count >= 2 && varBytes.Count < 4)
{
varReady = (UInt32)BitConverter.ToUInt16(varBytes.ToArray<byte>(), 0);
}
else
{
varReady = BitConverter.ToUInt32(varBytes.ToArray<byte>(), 0);
}
break;
}

How to use "using static" directive for dynamically generated code?

I want to let the users input mathematics expression in terms of x and y as natural as possible. For example, instead of typing Complex.Sin(x), I prefer to use just Sin(x).
The following code fails when Sin(x), for example, is defined by the user.
using Microsoft.CodeAnalysis.CSharp.Scripting;
using System;
using System.Numerics;
using static System.Console;
using static System.Numerics.Complex;
namespace MathEvaluator
{
public class Globals
{
public Complex x;
public Complex y;
}
class Program
{
async static void JobAsync(Microsoft.CodeAnalysis.Scripting.Script<Complex> script)
{
Complex x = new Complex(1, 0);
Complex y = new Complex(0, 1);
try
{
var result = await script.RunAsync(new Globals { x = x, y = y });
WriteLine($"{x} * {y} = {result.ReturnValue}\n");
}
catch (Exception e)
{
WriteLine(e.Message);
}
}
static void Main(string[] args)
{
Console.Write("Define your expression in x and y: ");
string expression = Console.ReadLine(); //user input
var script = CSharpScript.Create<Complex>(expression, globalsType: typeof(Globals));
script.Compile();
JobAsync(script);
}
}
}
Question
How to use using static directive for dynamically generated code?
You can supply script options to the Create function that define the references and imports that should be set for your script:
var scriptOptions = ScriptOptions.Default
.WithReferences("System.Numerics")
.WithImports("System.Numerics.Complex");
var script = CSharpScript.Create<Complex>(expression, options: scriptOptions, globalsType: typeof(Globals));
That way, you can use Sin(x) in the input:
Define your expression in x and y: Sin(x)
(1, 0) * (0, 1) = (0,841470984807897, 0)
However, when dealing with user input, you should consider writing your own parser. This allows you on one hand to define your own “aliases” for functions (e.g. a lower case sin) or even a more lenient syntax; on the other hand, it also adds more security because right now, nothing prevents me from doing this:
Define your expression in x and y: System.Console.WriteLine("I hacked this calculator!")
I hacked this calculator!
(1, 0) * (0, 1) = (0, 0)
I created a quick (and dirty) parser using Roslyn’s syntax tree parsing. Obviously this is rather limited (e.g. since it requires all return values of subexpressions to be Complex), but this could give you an idea of how this could work:
void Main()
{
string input = "y + 3 * Sin(x)";
var options = CSharpParseOptions.Default.WithKind(Microsoft.CodeAnalysis.SourceCodeKind.Script);
var expression = CSharpSyntaxTree.ParseText(input, options).GetRoot().DescendantNodes().OfType<ExpressionStatementSyntax>().FirstOrDefault()?.Expression;
Console.WriteLine(EvaluateExpression(expression));
}
Complex EvaluateExpression(ExpressionSyntax expr)
{
if (expr is BinaryExpressionSyntax)
{
var binExpr = (BinaryExpressionSyntax)expr;
var left = EvaluateExpression(binExpr.Left);
var right = EvaluateExpression(binExpr.Right);
switch (binExpr.OperatorToken.ValueText)
{
case "+":
return left + right;
case "-":
return left - right;
case "*":
return left * right;
case "/":
return left / right;
default:
throw new NotSupportedException(binExpr.OperatorToken.ValueText);
}
}
else if (expr is IdentifierNameSyntax)
{
return GetValue(((IdentifierNameSyntax)expr).Identifier.ValueText);
}
else if (expr is LiteralExpressionSyntax)
{
var value = ((LiteralExpressionSyntax)expr).Token.Value;
return float.Parse(value.ToString());
}
else if (expr is InvocationExpressionSyntax)
{
var invocExpr = (InvocationExpressionSyntax)expr;
var args = invocExpr.ArgumentList.Arguments.Select(arg => EvaluateExpression(arg.Expression)).ToArray();
return Call(((IdentifierNameSyntax)invocExpr.Expression).Identifier.ValueText, args);
}
else
throw new NotSupportedException(expr.GetType().Name);
}
Complex Call(string identifier, Complex[] args)
{
switch (identifier.ToLower())
{
case "sin":
return Complex.Sin(args[0]);
default:
throw new NotImplementedException(identifier);
}
}
Complex GetValue(string identifier)
{
switch (identifier)
{
case "x":
return new Complex(1, 0);
case "y":
return new Complex(0, 1);
default:
throw new ArgumentException("Identifier not found", nameof(identifier));
}
}

how to compare attribute values including comparison operators in C#

I am comparing two XML nodes which includes numeric values with comparison operators as shown below
<rule id="rule1" subject="user1" age="60" permission="granted"/>
<rule id="rule2" subject="user1" age=">=50" permission="denied"/>
This is a very simple example where the rule1 states that if the subject is user1 then the permission is granted if his age is 60 whereas the rule2 states that permission is denied for user1 if age is 50 or greater than 50. So it mean these rules are contradictory.
My question is that how could I compare the age attribute which is including numeric values and comparison operators. In the above example I conclude that both the rules have contradictory values.
I am using C# to compare these attribute values.
I would create a syntax tree from xml and use the tree to evaluate the conditions. As for how to evaluate comparison-based rule, you can write your own class like:
public enum BinaryOperator
{
LessThenOrEqual,
LessThen,
Equal,
GreaterThen,
GreaterThenOrEqual
}
public class BinaryOperatorEvaluator
{
public BinaryOperatorEvaluator(BinaryOperator op)
{
Operator = op;
}
public BinaryOperator Operator { get; private set; }
public bool Evaluate(IComparable x, IComparable y)
{
switch (Operator)
{
case BinaryOperator.Equal:
return x.CompareTo(y) == 0;
case BinaryOperator.GreaterThen:
return x.CompareTo(y) > 0;
case BinaryOperator.GreaterThenOrEqual:
return x.CompareTo(y) >= 0;
case BinaryOperator.LessThen:
return x.CompareTo(y) < 0;
case BinaryOperator.LessThenOrEqual:
return x.CompareTo(y) <= 0;
default:
throw new NotImplementedException();
}
}
public static BinaryOperatorEvaluator FromExpression(string expression, out int value)
{
var regexValidTerm = new Regex("^(?<operator>(<=|=|>=|<|>)?)(?<numeric>([0-9]+))$");
var match = regexValidTerm.Match(expression);
if (!match.Success)
{
throw new ArgumentException("Not a valid expression.", "expression");
}
var opValue = match.Groups["operator"].Value;
var op = BinaryOperator.Equal;
if (!string.IsNullOrEmpty(opValue))
{
switch(opValue)
{
case "<=":
op = BinaryOperator.LessThenOrEqual;
break;
case "=":
op = BinaryOperator.Equal;
break;
case ">=":
op = BinaryOperator.GreaterThenOrEqual;
break;
case "<":
op = BinaryOperator.LessThen;
break;
case ">":
op = BinaryOperator.LessThenOrEqual;
break;
default:
throw new NotImplementedException();
}
}
value = int.Parse(match.Groups["numeric"].Value);
return new BinaryOperatorEvaluator(op);
}
}
int number;
var bo = BinaryOperatorEvaluator.FromExpression("<=15", out number);
// false
var foo = bo.Evaluate(16, number);
// true
foo = bo.Evaluate(15, number);
// also true
foo = bo.Evaluate(14, number);
Add the runat="server" inside your tags, then access the attribute with rule1.Attributes["age"] within c# code. And overload operator for comparison if its logic requires this.
You might consider doing this in code behind, makes it a heck lot easier.
if(age > 50)
permission = "denied";
else if(age == 60)
permission = "granted";

Reflection.Emit create object with parameters

I'm creating a dynamic function to create an object at runtime given an object[] of constructor params. I keep getting the generic exception 'Operation could destablise the runtime' and I can't see what I've done wrong.
The method works fine if the created object needs no constructor arguments - so the problem must be in the code in the for loop.
The code indexes into the given object[] putting the object onto the stack after which the ctor is called and the object returned.
Any ideas???
internal static Func<object[], object> CreateObjectFactoryMethodWithCtorParams(ConstructorInfo ctor, int ctorArgsLength)
{
Func<object[], object> factoryMethod = null;
if (ctor != null)
{
var dm = new DynamicMethod(string.Format("_CreationFacotry_{0}", Guid.NewGuid()), typeof(object), new Type[] { typeof(object[])}, true);
var il = dm.GetILGenerator();
il.DeclareLocal(typeof(int));
il.DeclareLocal(typeof(object));
il.BeginExceptionBlock();
il.Emit(OpCodes.Ldc_I4_0); // [0]
il.Emit(OpCodes.Stloc_0); //[nothing]
for (int i = 0; i < ctorArgsLength; i++)
{
EmitInt32(il, i); // [args][index]
il.Emit(OpCodes.Stloc_0); // [args][index]
il.Emit(OpCodes.Ldarg_0); //[args]
EmitInt32(il, i); // [args][index]
il.Emit(OpCodes.Ldelem_Ref); // [item-in-args-at-index]
}
il.Emit(OpCodes.Newobj, ctor); //[new-object]
il.Emit(OpCodes.Stloc_1); // nothing
il.BeginCatchBlock(ExceptionType); // stack is Exception
il.Emit(OpCodes.Ldloc_0); // stack is Exception, index
il.EmitCall(OpCodes.Call, EmitGeneratorType.GetMethod("ThrowFactoryException"), null);
il.EndExceptionBlock();
il.Emit(OpCodes.Ldloc_1); //[new-object]
il.Emit(OpCodes.Ret);
factoryMethod = (Func<object[], object>)dm.CreateDelegate(typeof(Func<object[], object>));
}
else
{
throw new EmitGeneratorException("Cannot create instance factory for a null ctor instance");
}
return factoryMethod;
}
private static void EmitInt32(ILGenerator il, int value)
{
switch (value)
{
case -1: il.Emit(OpCodes.Ldc_I4_M1); break;
case 0: il.Emit(OpCodes.Ldc_I4_0); break;
case 1: il.Emit(OpCodes.Ldc_I4_1); break;
case 2: il.Emit(OpCodes.Ldc_I4_2); break;
case 3: il.Emit(OpCodes.Ldc_I4_3); break;
case 4: il.Emit(OpCodes.Ldc_I4_4); break;
case 5: il.Emit(OpCodes.Ldc_I4_5); break;
case 6: il.Emit(OpCodes.Ldc_I4_6); break;
case 7: il.Emit(OpCodes.Ldc_I4_7); break;
case 8: il.Emit(OpCodes.Ldc_I4_8); break;
default:
if (value >= -128 && value <= 127)
{
il.Emit(OpCodes.Ldc_I4_S, (sbyte)value);
}
else
{
il.Emit(OpCodes.Ldc_I4, value);
}
break;
}
}
Calling code
Func<object[], object> factoryFunction = GetFunction(someCtor, new object[] { arg1, arg2});
var obj = factoryFunction(new object[] {new SomeClass, "A String" }); //input ctor args
It works fine for me, as long as I make all the constructor parameters object:
class SomeClass {
public SomeClass(object s, object t) { }
}
static void Main()
{
var someCtor = typeof(SomeClass).GetConstructors()[0];
Func<object[], object> factoryFunction = CreateObjectFactoryMethodWithCtorParams(someCtor, someCtor.GetParameters().Length);
var obj = factoryFunction(new object[] {"A String", 123 });
}
I think the problem is that you haven't done any conversions from the objects from the array to the actual constructor types, noting that you need to consider both reference types and value-types (unbox). Like so:
var parameters = ctor.GetParameters();
for (int i = 0; i < parameters.Length ; i++)
{
EmitInt32(il, i); // [index]
il.Emit(OpCodes.Stloc_0); // [nothing]
il.Emit(OpCodes.Ldarg_0); //[args]
EmitInt32(il, i); // [args][index]
il.Emit(OpCodes.Ldelem_Ref); // [item-in-args-at-index]
var paramType = parameters[i].ParameterType;
if (paramType != typeof(object))
{
il.Emit(OpCodes.Unbox_Any, paramType); // same as a cast if ref-type
}
}
il.Emit(OpCodes.Newobj, ctor); //[new-object]
il.Emit(OpCodes.Stloc_1); // nothing
as a minor note: since you need to call .GetParameters(), you should not pass in the parameter length as a parameter to the method; that is redundant, and could cause errors when wrong.
This then works with my exmaple:
class SomeClass {
public SomeClass(string s, int t) { }
}
static void Main()
{
var someCtor = typeof(SomeClass).GetConstructors()[0];
Func<object[], object> factoryFunction = CreateObjectFactoryMethodWithCtorParams(someCtor);
var obj = factoryFunction(new object[] {"A String", 123 });
}

Categories

Resources