SlovenianSearchQueryManager.ApplySloveniaQueries(rawQuery, page, pageSize, orderBy, out count);
is it possible to get SlovenianSearchQueryManager class by concatinating HttpContext.Current.Session["lang_name"] and "SearchQueryManager";
HttpContext.Current.Session["lang_name"] is Slovenian so together is SlovenianSearchQueryManager
next time
HttpContext.Current.Session["lang_name"] is German so together is
GermanSearchQueryManager
i try to make this generic instead of making
if (HttpContext.Current.Session["lang_name"] == "Slovenian)
{
SlovenianSearchQueryManager.ApplySloveniaQueries(rawQuery, page, pageSize, orderBy, out count);
}
else ...
i want to make something like
(HttpContext.Current.Session["lang_name"] + "SearchQueryManager").ApplySloveniaQueries(...
is this even possible to make something like this and the type SlovenianSearchQueryManager for example exists, it's in a different class library.
You should make an ISearchQueryManager interface with implementations for each language, then use a Dictionary<string, ISearchQueryManager> to get the implementation for the desired language.
Use Type.GetType and Activator.CreateInstance:
var queryManagerType = Type.GetType(HttpContext.Current.Session["lang_name"] + "SearchQueryManager");
var queryManager = Activator.CreateInstance(queryManagerType);
Activator.CreateInstance returns an object. You might want to define an interface that you query managers will need to implement.
public interface ISearchQueryManager {
void ApplyQueries(/* add parameters here */);
}
Then you can cast the object returned by CreateInstance to the interface:
var queryManagerType = Type.GetType(HttpContext.Current.Session["lang_name"] + "SearchQueryManager");
var queryManager = (ISearchQueryManager)Activator.CreateInstance(queryManagerType);
queryManager.ApplyQueries(rawQuery, page, pageSize, orderBy, out count);
I would recommend making two changes.
First, make all of your "SearchQueryManager" instances derive from a common interface (or base class), such as ISearchQueryManager.
Second, make a Dictionary<string, ISearchQueryManager>, and use it to lookup the appropriate one based on your type.
You could then do:
ISearchQueryManager manager;
if (!managers.TryGetValue(HttpContext.Current.Session["lang_name"], out manager))
{
// Unknown language - handle this!
}
else
{
manager.ApplyQuery(...);
}
You're looking at the factory pattern. Define an interface, like IQueries with the queries methods you need. Then define a factory class that takes your language and returns an IQueries. For slovenia, return your SlovenienSearchQueryManager. Etc for other languages.
It sounds like you're trying to work around creating a factory pattern, which would, IMO, be the correct way to solve this problem.
http://aspalliance.com/809
I would investigate using a factory class to create your query managers.
Pseudo-code:
var factory= new QueryManagerFactory();
var queryManager = factory.Create("Slovenian");
In your factory create method return the type of query manager you want based upon the input.
Related
I'm learning the power of generics in C# in conjunction with NHibernate. I'd like to attempt the following in the pasted code.
In an attempt to do some post processing of N number of NHibernate objects I worked on a utility method leveraging generics to make it applicable to all NHibernate mapping classes we use now, or in the future. It works but I need to hard code each call for each mapping class. This is a pain and will need continuing updating as our schema and mappings change over time.
I do have an ever up-to-date list of all mapping classes by string name through the NHibernate mappings I generate on the fly. If there was a way to use this list of string names to call my generics based method, I'd be super happy.
Can anyone tell me if this is possible? Do I need to find another route?
Thanks so much in advance!!!
public static void ProcessSomeItems()
{
// *************************************************************
// As of now I have to list all classes as such to be processed
// It works but I have to update manually when new mapping classes are created
// *************************************************************
NHibDoSomethingUtil<AspnetMembership>();
NHibDoSomethingUtil<AspnetProfile>();
NHibDoSomethingUtil<AspnetRole>();
NHibDoSomethingUtil<AspnetUser>();
// and so forth...
// I have a up-to-date list of all mappings from "HbmMapping" and can get a list of all in the
// list form as below
List<string> mappingNames = new List<string>();
foreach (string mappingName in mappingNames)
{
Type theType = Type.GetType(mappingName);
// I know I'm getting Types and Generics classes and so forth all jumbled but
// how in the heck would I do something like the below?
NHibDoSomethingUtil<theType>(); // Obviously doesn't compile ;-)
}
}
// Generic method
public static void NHibDoSomethingUtil<T>() where T : class
{
using (ISession session = sourceDBSessionFactory.OpenSession())
{
foreach (dynamic item in new List<T>(session.QueryOver<T>().List()))
{
// Process item;
}
}
}
ecsousa gave great input and I was able to accomplish what I needed with something like the following.
foreach (HbmClass mappingClass in mapping.Items)
{
Console.WriteLine(" -- Discovered Mapping: " + mappingClass.Name);
Type mappingClassType = Type.GetType(mappingClass.Name);
var genericMethod = typeof(Migration).GetMethod("NHibDoSomethingUtil");
var method = genericMethod.MakeGenericMethod(mappingClassType);
method.Invoke(null, null);
}
You will need to use Reflection in order to accomplish this. Instead of directly calling NHibDoSomethingUtil, try this:
var genericMethod = typeof(TheClassName).GetMethod("NHibDoSomethingUtil");
var method = genericMethod.MakeGenericMethod(theType);
method.Invoke(null, null);
Note that you have to replace TheClassName by the class containing both methods.
Keep in mind the this kind of code is slow, and you should use it very carefully.
I'm creating a list of my defined objects like so
List<clock> cclocks = new List<clocks>();
for each object in the list i'm calling a method moveTime, like so
foreach(clock c in cclocks)
{
c.moveTime();
}
is the a way i can write some cleaver thing so i can call
cclocks.moveTime();
it would then go though the list doing that method
I guess I want to create a collection method?
I'm guessing there must be some thing I can do I just don't know what.
thanks for your help
You could write an extension method on List<T> which iterates this and calls moveTime() on each of the items in the collection. See this article for more information.
This approach obscures a lot of information, though. If I we're you, I'd go with the for-loop. And if you're just calling one method on each of the objects, you can shorten the for-loop, like so:
// no need to declare scope if you're just doing one operation on the collection
foreach(var object in collection) object.method();
... Or use LINQ:
collection.ForEach(object => object.method());
I'm not quite sure but perhaps you are talking about ForEach() method of List<T>
cclocks.ForEach(c => c.MoveTime());
You could write an extension method to do this.
http://msdn.microsoft.com/en-us/library/bb383977.aspx
You can either create a class that inherits from
List<clock>
or create an extension method for List<clock>
Another solution is to derive new class from List<Clock> and then add all the methods you need. Something like this:
public class ClocksList : List<Clock>
{
public void MoveSingleClock(Clock clock)
{
clock.MoveTime();
}
public void MoveAllClocks()
{
foreach(clock c in InnerList)
{
MoveSingleClock(c);
}
}
}
You can use new class like this:
ClocksList clocks = new ClocksList();
// Fill the list
clocks.Add(new Clock());
...
// Move time on all clocks
clocks.MoveAllClocks();
// Move single clock
Clock c = new Clock();
clocks.Add(c);
clocks.MoveSingleClock(c);
I have a custom list which inherits from Generic.List<T> like this:
public class TransferFileList<T> : List<TransferFile> { .. }
When I set (where 'Files' is a TransferFileList<T>):
var files = uploadResponse.Files.Where(x => !x.Success).ToList()
the 'files' object resolves as System.Collections.Generic.List<TransferFile>, not TransferFileList<T>, which is what I would expect as it was what was being filtered through the Where, so how could I successfully return a list of TransferFileList<T> into 'files'?
I did try:
var files = uploadResponse.Files.Where(x => !x.Success).ToList()
as TransferFileList<TransferFile>;
but using that safe cast, it just resolves as null.
Thanks guys and gals.
First, I have to ask why you are inheriting from List<T>? 99% of the time that's a bad idea.
If you want to extend the functionality of a list, use extension methods:
public static something PrintErrors(this List<TransferFile> list)
{
//do your printing logic
}
On to the answer: ToList() operates on an IEnumerable<T> and converts the members of the sequence to a List of the same type. Since you inherit from List<T> which implements IEnumerable<T>, that's what happens there.
Where() works the same way - operates on an IEnumerable<T> and returns an IEnumerable<T>.
To get some arbitrary list-like object back, like you have, you need to add the items in a sequence to your custom list, like so:
var myFiles = new TransferFileList<TransferFile>();
myFiles.AddRange(originalFileList.Where(condition));
You can add an extension method for IEnumerable<TransferFile> to handle that scenario:
public static TransferFileList ToTransferFileList(
this IEnumerable<TransferFile> files)
{
return new TransferFileList(files);
}
// ...
var files = uploadResponse.Files.Where(x => !x.Success).ToTransferFileList();
This provides you with the TransferFileList instead of just a List<TransferFile>. Note the reason your as returns null is because while TransferFileList is a List<TransferFile>, the same does not hold in the other direction. That is, your List<TransferFile> is NOT a TransferFileList object.
I agree with #RexM that any attempt at subclassing List<T> be avoided due to the multitude of pitfalls associated. I suggest Composition (Has-A rather than Is-A) or sticking with the base class library collections instead.
Thanks guys.
I like SLV's extension approach, but is there any other straight casting approach?
If not I might just go with the reverted in-line approach I was hoping to avoid:
var transferFiles = new TransferFileList<TransferFile>();
if (files != null)
transferFiles.AddRange(files);
if you take a look at the following code, you will (hopefully) see what I am trying to archieve. Basically this code does:
A query for generic storag items (they store their type as string)
If the item is a subclass of SearchCriteria, create the correct instance
Add the instance to the list (SearchCriteria is superclass)
Not very elegant is, of course, the pseudo-switch case, which I would have to update for all different criteria I create.
So, my question, is there a "generic" way to create an instance which is strongly typed using a string as "source" for the type.
I know I can use Reflection to create an instance, but this is of type object, so I would not be able to add it to the list. Oh, just got an idea... Create object using reflection, cast it to supertype (SearchCrit), add to list. Real type should still be the "correct subtype" I hope...
Will try it, and update this post with results. Any better ideas?
Chris
private IList<SearchCriteria> _searchCriteriaAll;
public IList<SearchCriteria> SearchCriteriaAll
{
get
{
if (_searchCriteriaAll == null)
{
_searchCriteriaAll = new List<SearchCriteria>();
var tN = typeof (SearchCriteria).ToString();
foreach (var o in DataStorage.LinkedObjects)
{
if (tN.StartsWith(o.TypeName))
{
if (o.TypeName == typeof(StringSearchCriteria).ToString())
_searchCriteriaAll.Add(new StringSearchCriteria(o));
}
}
}
return _searchCriteriaAll;
}
}
EDIT:
Thanks for the tips, the "correct" way would definitly be the factory pattern. I will look into that. For now, I use this hack, because the subclasses are so small, I dont want a factory for each one.. (and this place is currently the only one with such a "fancy" feature)
private IList<SearchCriteria> _searchCriteriaAll;
public IList<SearchCriteria> SearchCriteriaAll
{
get
{
if (_searchCriteriaAll == null)
{
_searchCriteriaAll = new List<SearchCriteria>();
var tN = typeof (SearchCriteria).ToString();
foreach (var o in DataStorage.LinkedObjects)
{
if (tN.StartsWith(o.TypeName))
{
var newO = Activator.CreateInstance(typeof(SearchCriteria).Assembly.FullName, o.TypeName);
var newCrit = newO.Unwrap() as SearchCriteria;
newCrit.DataStorage = o;
_searchCriteriaAll.Add(newCrit);
}
}
}
return _searchCriteriaAll;
}
}
Generics and reflection don't make good friends. A simpler approach here is to use the non-generic list interface:
_searchCriteriaAll = new List<SearchCriteria>();
IList list = (IList) _searchCriteriaAll;
...
Type type = typeof(SearchCriteria).Assembly.GetType(o.TypeName);
list.Add(Activator.CreateInstance(type));
(where o.TypeName includes the namespace information, but doesn't have to be assembly-qualified)
This is still runtime type-safe (it'll throw at runtime if it is wrong), and still adjusts the same list.
Note also that we only look inside Assembly directly via Assembly.GetType().
I'd say you're looking for the Factory Method Pattern.
There's a C# sample here - the first link explains the pattern better, the second is the right language for you.
It's not entirely clear to me what you are trying to achieve, but you can create a Type from a string like this:
var t = Type.GetType(typeName);
If you want to examine whether it's a proper subtype, you can use the IsAssignableFrom method.
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.