Factory to create AND instantiate object, based upon a string? - c#

I have a request to read string messages from a queue and "process them". Each message has a 4 digit "identifier/key" a the start, followed by date, time and another number...from then on, each message is different and requires different processing.
My thought was to use a factory to create an object of the required type and ALSO call the asbtract constructor at the same time.
Is this a sensible approach to take?
If so...how?
e.g.
1000,2013-02-13,09:00:00,492,....................
4000,2013-02-13,09:00:01,492,....................
1000,2013-02-13,09:00:02,74664,....................
4003,2013-02-13,09:00:03,1010,....................
4000,2013-02-13,09:00:04,493,....................
To build object of classes
Message1000 : AbstractMessage, IMessageThing
Message4000 : AbstractMessage, IMessageThing
Message4003 : AbstractMessage, IMessageThing
Where AbstractMessage contains a default constructor and properties for key, date, time, number etc.

If it makes sense depends on your requirements.
You could analyse the string like this:
// inside your actual factoryMethod...
var lines = ...;
foreach(var line in lines)
{
var tokens = line.Split(',');
// for split: you can also specify the max. amount of items if the ..... part can
// consist of more the dots.
CreateMessageObject(tokens); // eventually add to list of AbstractMessage or whatever
}
static FactoryClassConstructor()
{
_typeMap = new Dictionary<string, Type>();
_typeMap.Add("Message1000", typeof(Message1000));
// todo: add other message types
// you also could write a method which will use the class name of the
// type returned by typeof(XYZ) to assure the correct value as key
}
private Dictionary<string, Type> _typeMap;
private AbstractMessage CreateMessageObject(string[] tokens)
{
// simple error checking
if(tokens.Count != 5)
// todo: error handling
return null;
var type = typeMap[tokens[0]];
var instance = Activator.CreateInstance(type);
instance.Date = DateTime.Parse(tokens[1]);
instance.Time = DateTime.Parse(tokens[2]);
// todo initialize other properties
}
Of course you still need to do some error handling but I hope I could give you a good starting point.
The reason why i would use a dictionary is performance. Activator.CreateInstance is not very fast and the lookup with Type.GetType is also slow.
Instead of using the type as Value in the Dictionary you could also use something like this:
Dictionary<string, Action<IMessageThing>> _factories;
_factories = new Dictionary<string, Action<IMessageThing>>();
_factories.Add("Message1000", () => new Message1000());
and to create your object you could call:
var instance = _factories["Message1000"]();

Yes you can and is a correct and sensible approach. The things change a little if you can have a default constructor or not, and changes too if constructor will differ from one concrete implementation to the other. The simplest approach is to have a parameterless constructor.
With this prerequisite you can have something like this:
Type t = Type.GetType(string.Format("Handlers.MyHandlers.Message{0}",messageType));
var handler = Activator.CreateInstance(t) as IMessageThing;
In order to pass the string to the message, you can have a function defined in the IMessageThing interface, lets call it Init that you call immediately after the message creation, or probably better, have a costructor taking a string in the AbstractMessage class, and call it in the activator like this:
var handler = Activator.CreateInstance(t,body) as IMessageThing;
In the constructor of AbstractMessage call an abstract function Init(string body), so each concrete message need to implement its own parser.
Add some more error handling, and you have done.

One way is to split the string on , but set the max count to say 5, this should group all the values AFTER the number as one value:
var parts = your_string.split(new char[] {','},5);
Then you just need to use Activator.CreateInstance() to create your message instance. For example:
Type type = Type.GetType(String.Format("Message{0}",parts[0]));
var instance = Activator.CreateInstance(type) as IMessageThing;
You can then fill out the rest of the properties from parts.

You can either pass each message to a handler, the handler will check if it can handle this type of message. If so it will parse and return some object, otherwise it will return e.g. null and you will know to ask a different handler.
Or you build a parser that knows about the initial part that follows a common format, and then use a lookup table to find a specific message handler that will parse the remaining message and instantiate the correct type. (Pass the common parts to its constructor).
I don't understand what you mean with "create an object of the required type and ALSO call the asbtract constructor". There is no such thing as an abstract constructor. If you mean a constructor of an abstract base class, it is inevitable that it will get called when a subclass is instantiated.

Related

Modifying Reference to Object to Avoid Protected Setter

I have an abstract class that is generic like so:
class AbstractClass<T>
{
public T Data {get; protected set;}
}
In all cases T is an IEnumerable. In most cases its a List. But in a special case T can be a string, which is a collection of chars. What is the best way to permit Data to be modified when T is a string?
My thought is to simply get the value of Data, then assign it a new value;
var data = Obj.Data;
data = "string";
Will that do what I expect? Are there any pitfalls? Is there a better way?
Edit:
The underlying reason the setter is protected is because it is most often a collection, and the intent is to new the collection in the constructor. Secondly, and I probably should have added this, the Data object is optionally a INotifyPropertyChanged. There is some boilerplate code in the rest of the class, but the basic premise is that I don't want to worry about tracking the assignment of Data in the notifications.
class Concrete<T> : AbstractClass<T>
{
public Concrete(T t)
{
Data = t;
}
}
string str = "String";
Concrete<string> blah = new Concrete<string>(str);
Console.WriteLine(blah.Data); // "String"
string temp = blah.Data;
temp = "Assign";
Console.WriteLine(blah.Data); // "Assign"
I want the last line to print "Assign", but it prints "String". Is there a way to accomplish this without changing the protection? I'm thinking in terms of C++ where the address could just be modified.
C# strings are immutable so you can't just edit them like a collection.
However, there are other classes that can be used as mutable strings. I will be using System.Text.StringBuilder.
Instead of giving a generic argument of string, give it StringBuilder:
string str = "String";
var blah = new Concrete<StringBuilder>(new StringBuilder(str));
Console.WriteLine(blah.Data); // "String"
// to change the string to "Assign", call Clear() then Append()
blah.Data.Clear();
blah.Data.Append("Assign");
Console.WriteLine(blah.Data);
If you really want to do this, you could use the ref keyword. Since c# 7, you can also use ref for returning values from a function, see:
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/ref#reference-return-values
However, just because you could, doesn't mean you should. There is probably something wrong with your design if you have to do this.

C# cast object to another type stored in string variable

I have class MyWord and many other classes such as Noun, Idiom etc. that inherits from MyWord.
I store those objects in one list:
List<MyWord> Dictionary;
When I Add new element to the list i do it like this:
var myWord = new MyWord(id, word, definition,type,DateTime.Now.ToShortDateString());
Dictionary.Add(myWord);
As you can see, I put there object MyWord. I would like to be able to create for example Noun object and put in into list, like this:
var myWord = new Noun(id, word, definition, type, DateTime.Now.ToShortDateString());
Dictionary.Add(myWord);
The type parameter is a string, for example "noun". I use this method to get Type based on this string:
private Type GetFullType(string myType)
{
//Returns list of all types that inherit from MyWord class
var supportedTypes = (AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(assembly => assembly.GetTypes())
.Where(type => type.IsSubclassOf(typeof(MyWord)))).Select(x => x.FullName).ToList();
return Type.GetType(supportedTypes.Find(x => x.Contains_SkipWhiteSpacesIgnoreCase(myType)));
}
Now I don't know how to use the GetFullType() return value to convert MyWord to Noun. Like this:
Type wordType = GetFullType(type);
var myWord = new MyWord(id, word, definition, type, DateTime.Now.ToShortDateString());
Dictionary.Add((wordType)myWord);
I hope I explained myself clearly.
Note that I could use If...else structure to create different objects checking the type variable but it's not an elegant solution. Any better ideas?
You can use Activator.CreateInstance to create an instance of a type. See https://msdn.microsoft.com/en-us/library/wccyzw83(v=vs.110).aspx
var myword = Activator.CreateInstance(wordType);
And then you can set the properties on it using reflection, or by casting it to the base class MyWord.
OR you could use reflection on the wordType to find its constructor and call that.
BUT really, are there that many word types that it's not easier (and a whole lot faster) to maintain a Dictionary<string,Func<string, string, WordType>> where you can look up a word type and get a function that makes one for you from its word and definition values?
wordFactories["noun"](word, definition);
Another alternative is to use Impromptu.Interface from Nuget which can wrap any dynamic object in an interface and have it behave just like that. In my natural language engine for .NET that's what I use to take a word from a database and then wrap it up as, say, an INoun, an IPluralNoun, an IMammal, etc.
What you try to do is still not possible, becuase if we take a look at this:
Type wordType = GetFullType(type);
var myWord = new MyWord(id, word, definition, type, DateTime.Now.ToShortDateString());
Dictionary.Add((wordType)myWord);
You create an instance of MyWord, which could not be casted in Noun or some thing like that, because it is no type of that. What you can use is Activate.CreateInstance for your purpose. Take a look at it here: Activator.CreateInstance
This static method also allows to take a list of parameter, which will automatically passed to the constructor. But be sure, this use reflection and is always slower than creating instances with the new keyword.

Add to list when list type is not known until runtime

I have method which accepts an object. This object I know is a List<T> however T may vary between children of a base class at any one time when being passed into the method.
So if my base class is MonthType, and I have children called BlockMonthType and AreaMonthType the object passed in could be anyone of List<BlockMonthType> or List<AreaMonthType>.
I want to be able to add items to this object however when I cast it it seems to make a copy and the original object is not updated.
I'm doing this to cast:
var objectList = ((IEnumerable<MonthType>)graphObject.Source.Object).ToList();
Now I want to create a new item and add it to the list
// where ObjectType is a Type variable containing BlockMonthType
var newObject = (BlockMonthType)Activator.CreateInstance(graphObject.Source.ObjectType);
objectList.Add(newObject);
// and carry on the world is good
This works in so far as objectList has a newObject added. However the original variable isn't updated so when I leave the method it's back to it's original state. I know the object is a List<> when passed in as I can see it in the debugger as such.
Is there anyway I can accomplish this?
Here is a cut down version of the method I'm using it in.
public TraverseGraphResult Write(ObjectGraph graphObject)
{
var objectList = ((IEnumerable<MonthType>)graphObject.Source.Object).ToList();
var newObject = (MonthType)Activator.CreateInstance(rule.ObjectType);
newObject.Month = rule.Month;
objectList.Add(newObject);
// Other stuff as well is done but that's the crux of it
}
Hopefully this gives it more context. The method is being used to try and navigate a large object tree with many class types. I'm trying to add a new class type handler which will deal with adding and removing items from a list.
// This is being used in a recursive method to loop down a object's property tree
// .. more code here
// where properties is a List<PropertyInfo>
foreach (var pInfo in properties)
{
if (IsList(pInfo.PropertyType))
{
var enumerable = (IEnumerable)pInfo.GetValue(currentObjectGraph.Source.Object, null);
var sourceEnumerator = enumerable.GetEnumerator();
var graph = new ObjectGraph(enumerable, pInfo.Name);
// this part is made up but essentially the code looks up a list of objects that can deal with this
// particular one and returns it. We then call the write method on that object
var something = GetInterfaceHandlerForObject(enumerable);
something.Write(graph);
}
}
You should make your method generic:
public void MyMethod<T>(List<T> objectList) where T:class, new()
{
objectList.Add(new T());
...
}
Casting is rarely ever necessary when you use generics. Also, your ToList() is causing a new copy of the list to be created.
One drawback to this approach is that T needs to have an empty constructor. If you need to construct an object with parameters you could instead pass in a Func<T>. You can then call it passing in a lambda expression like: (x) => new BlockMonthType(someParameter, orAnother).
I ended up resolving this by storing the underlying List T type in the ObjectGraph object and casting to that when required.
var objectList = ((IEnumerable)graphObject.Source.Object).Cast(monthAllocationRule.ListType);
Without the correct cast objectList was either null or a copy of the list. Now I can add to objectList and know it's added to the source object.
Probably not idea as Ian mentioned above but did the trick.

Evaluating a set of rules defined in a string

I made a system that creates a simple string with Function/Response format, example:
Check('Value'):ShowImage(#)|Check('Value'):OtherFunction(#)....and so on
Where Check is the name of a function, Value is the parameter, ShowImage is the name of a Response function, # is the entry paremeter (result of the previous function). The pipe splits another Function/Response pair that fires if the first Check('Value') function once "checked" were not satisfied (say, if the parameter was not accomplished the Check condition the function is invalid and hence the Response part in the first Function/Response pair is not executed, so system keep trying Functions awaiting to find the one that executes the right Response).
The way the application should work is to evaluate each rule (similar to a JavaScript eval function) and take appropriate action based on function results.
At first glance, it looks complicated, because first of all I need to cast the string to the right real C# function that will actually process the condition. Therefore, depending on the function result, decide where to point to execute my Response function.
Furthermore: This is just the kind example, because there are functions as * that represent something like: "any condition is true" what in almost all cases this function is the last in the chain (the default function).
That's my problem, I can't realize what is the easiest way to cope with this problem.
Maybe a chain of delegates? Lambdas? Anonymous stored into a structure...
Could you give me your measure/advise? Where to start?
Depending on the level of extensibility you want to have, I would say the most extensible way would be to use reflection to get method references, after you have parsed the input string.
You can start by splitting your problem into smaller subproblems.
Let's say you are aiming for something like this:
static void Main(string[] args)
{
string rules =
"Check(Morning):Say(Good morning)|" +
"Check(Afternoon):Say(Good afternoon)|" +
"Check(Evening):Say(Good night)";
// next, you need some **object instances** which will
// provide a context for your "test" and "action" methods.
// you don't want to use static methods if you
// went through the pain of defining such an architecture!
// let's say that a "Tester" object has a "Check" method,
// and an "Executor" object has a "Say" method:
var tester = new Tester("Afternoon");
var executor = new Executor();
// since I suck at regular expressions,
// I am using plain string methods to split
// the expression into tokens. You might want
// to add some validation
foreach (var rule in rules.Split('|'))
{
var result = Parse(rule, tester, executor);
if (result.TestPassed)
{
result.Execute();
break;
}
}
}
A "result" as it's used above would then have an interface like this:
public interface IResult
{
// returns true if a test is fulfilled
bool TestPassed { get; }
// executes the related action
void Execute();
}
And, if you want to delegate actual actions to some unknown methods, a reasonable way to implement it would be something like this:
public class Result : IResult
{
#region IResult Members
private readonly Func<bool> _testMethod;
public bool TestPassed
{
get { return _testMethod(); }
}
private readonly Action _actionMethod;
public void Execute()
{
_actionMethod();
}
#endregion
public Result(Func<bool> testMethod, Action actionMethod)
{
_testMethod = testMethod;
_actionMethod = actionMethod;
}
}
What's left is to use some reflection to get the actual methods out of your strings:
private static IResult Parse(string rule, object tester, object executor)
{
// split into test/action
var tokens = rule.Split(':');
// extract the method/parameter part for each expression
var test = GetMethodAndParams(tokens[0]);
var action = GetMethodAndParams(tokens[1]);
// use reflection to find actual methods
var testMethod = tester.GetType().GetMethod(test.Method);
var actionMethod = executor.GetType().GetMethod(action.Method);
// return delegates which will simply invoke these methods
return new Result
(
() => (bool)testMethod.Invoke(tester, new object[] { test.Param }),
() => actionMethod.Invoke(executor, new object[] { action.Param })
);
}
That is, more or less, your program's skeleton. You should be able to fill in the missing parts yourself, as an exercise. If you have problems, I can update the answer later.
A GetMethodAndParams method should split the input string into a Tuple (or your custom class) which contains the method name and its params as plain strings. Tester and Executor classes can also be implemented trivially.
It looks like you want a pattern along the lines of the .NET TryParse() methods. In that case, you would modify your check method to have an out parameter that is the value (represented in your example by #).
int result;
if(Check('Value', out result))
ShowImage(result);
else(Check('Value2', out result))
OtherFunction(result);
Finally I'm back here to post what I've done few weeks ago to solve this situation.
It was easy.
Regex class provide few options, one of those is "Explicit Catpure", all streams with the form (?) can be handled as strong typed parameters so, if the named group "IsNotEmptyorNull" then the function is present and it is promotable to casting using the form Enum.Parse("").
Snipet:
Regex rx = new Regex(#"(?<function>Check|BooleanOp)\('(?<param>[\w]+)'\){1}:(?<action>[\w]+){1}", RegexOptions.ExplicitCapture);
Match m;
Dictionary<FunctionArray, String> actions = new Dictionary<FunctionArray, String>();
if((m=rx.Match(strStream)).Success)
{
actions.Add((FunctionArray)Enum.Parse(typeof(FunctionArray), m.Groups["function"].value, true), m.Groups["param"].value);
}
Of course, there are lost the action part so I've improved the Dictionary stuff with an specialized Struct that can handle the functions and values as a source for decision taking.
Thanks to all. Ed.

Best way to decide which subclass is needed

I am working on a large-scale checkout application for a current project.
This checkout has many cases depending on the user's admin level, how they got to the checkout, and what type of item they are checking out, and so the process is abstracted away from the .aspx pages via a set of context classes.
These classes all subclass from a single class, CheckoutContext, and the type of class to be used is noted via an enum.
Is there something similar to typedef I can use to choose which subclass to use, or should I simply have a method that returns the relevant class, like so:
CheckoutContext chooseSubclass(CheckoutCase c)
{
CheckoutContext output;
switch (c):
{
case CheckoutCase.SingleItemNew:
output = new SingleItemNew;
break;
case . . .
return output;
}
}
What you're implementing is a Factory Pattern. This is a standard practice, though it typically means writing a lot of repetitive code (much like your switch statement, which is often how they're implemented). You could do all sorts of fancy things like dynamic instantiation via reflection, but don't play with fire. Just stick with switch statement and you'll be fine.
If there are a large number of cases, I would create a Dictionary<CheckoutCase, Type> and populate it one time with the set of all CheckoutCase values and corresponding CheckoutContext Types. Then you could use Activator.CreateInstance to return the appropriate type instead of a gigantic switch statement.
You could implement this with a custom attribute and a factory method. Make all you Sub Classes implement a CustomAttribute say CheckOutCaseScenarioAttribute that takes the CheckOutCase Enum value.
Within your factory method, look for types that have this Enum Value set and create the object. This will avoid your switch case. This will work if you dont have any other initialization logic within your factory method.
This is called a Factory Design Pattern. I would create a static method that returns the needed class. A good practice here is to implement an Interface and return the interface.
interface ICheckoutItem
{
void CheckOut();
}
Have your items implement the interface. Then in your factory method return the interface of each item.
ICheckoutItem chooseSubclass(CheckoutCase c)
{
ICheckoutItem output;
switch (c):
{
case CheckoutCase.SingleItemNew:
output = new SingleItemNew;
break;
case . . .
return output;
}
}
You can create an attribute that has one property which would be the type of CheckoutContext:
public class CheckoutContextAttribute : Attribute
{
public Type CheckoutType{get;set;}
}
Then, on your enum, you can put the correct attribute on the correct enum type:
public enum CheckoutCase
{
[CheckoutContext(CheckoutType=typeof(SingleItemNew)]
SingleItemNew,
...
...
}
Then, in that method where you need to send back the correct Context type you use reflection and do something like this:
public CheckoutContext GetContext(CheckoutCase c)
{
FieldInfo field = c.GetType().GetField(c.ToString());
object[] attribs = field.GetCustomAttributes(typeof(CheckoutContextAttribute),false);
CheckountContext result = null;
if(attribs.Length > 0)
{
CheckoutContextAttribute attrib = attribs[0] as CheckoutContextAttribute;
Type type = attrib.CheckoutType;
result = Activator.CreateInstance(type) as CheckountContext;
}
return result;
}
This should do the trick. Just add some null / error checking to be safe.

Categories