Generic Method returning different generic collections - c#

Hi I have a Method like this:
public T LoadR<T, K>()
where T : ObservableCollection<K>, new()
where K : IStoreElement, new() {
T onC = new T();
//....
return (onC);
}
Further I have a class XObservableCollection which derivies from ObservableCollection.
It works as it is when I call:
Categories = LoadR<ObservableCollection<Category>,Category>();
Products = LoadR<XObservableCollection<Product>,Product>();
What I want to do is to make a call like this (avoid passing the K as extra parameter):
Categories = LoadR<ObservableCollection<Category>>();
Products = LoadR<XObservableCollection<Product>>();
I know that I could write an extension for it.
But I curious if there is a way to achive this without it.
Manfred

I don't think you can.
C# has a mechanism to understand generic agruments from method paramaters when used in it, but not from other generic arguments of the same method. It doesn't work.
Maybe you can change your signature to:
private static ObservableCollection<K> LoadR<K>(.ObservableCollection<K> onC)
where K : IStoreElement, new()
{
//....
return onC;
}
Usage would be:
static void TestLoad()
{
var result1 = LoadR(new ObservableCollection<Something>());
var result2 = LoadR(new DerivedClassFromObservableCollection<Something>());
}
Which I agree is not that good, and I can se it's not what you are looking for.
But just because C# wouldn't let you try to infer the types from the generic arguments.
.....
The other way aroudn is to make it use a specific collection. I can see you don't want this even more.
So, one thing you can do is make it return IEnumerable instead, then you usage will be something like:
static void TestLoad()
{
var result1 = new ObservableCollection( LoadR<Something>() );
var result1 = new DerivedClassFromObservableCollection( LoadR<Something>() );
}
Which may not be good also if you want to do fancy things with the collection itself, because you no-longer own it.
....
I would go for the very first option myself.

Related

Replace switch statements for child class type

There is a method that accepts 2 parameters:
int selectedClass;
int selectedFunction;
Next, there goes 2 switch statements. First of all, it determines child class type using enum:
ParentClass p;
switch(selectedClass){
case (int)ClassTypes.A:
p = new classA();
break;
case (int)ClassTypes.B:
p = new classB();
break;
case (int)ClassTypes.C:
p = new classC();
break;
}
And it goes on an on for like 50 more statements. Furthermore, there is another switch statement that determines a function:
string result;
switch(selectedFunction){
case (int)FunctionTypes.Func1:
result = p.function1();
break;
case (int)FunctionTypes.Func2:
result = p.function2();
break;
case (int)FunctionTypes.Func3:
result = p.function3();
break;
}
I did use the search, there are a lot of examples of improving the second switch statement, but not the first one. The 1st question is: how do we determine both child class and function with no switch statements?
2nd: In js I would do something like that:
functionsArray[selectedClass][selectedFunction]();
Is it possible to implement similar kind of mapping in c#?
Update #1:
I have replaced the 1st switch with the following code:
public static Dictionary<ClassTypes, Type> typeDict = new Dictionary<ClassTypes, Type>()
{
{ ClassTypes.A , typeof(classA) },
{ ClassTypes.B , typeof(classB) },
{ ClassTypes.C , typeof(classC) }
};
ParentClass p = (ParentClass)Activator.CreateInstance(typeDict[selectedClass]);
I can't say I understand the logic that lead you to pick this strange design, but I can think of at least two ways to improve it, providing all the functions you are calling are implemented in the base class (and overriden when needed in the derived classes, of course).
Both solutions are only relevant in case all classes provides a parameter-less constructor and parameter-less functions, and executing the functions does not require further initialization:
The first solution would require you to change the method signature, and force the calling method to know the types of the classes so you might not be able to implement it but it involves far less code.
ExecuteMethod<TClass>(Func<TClass, string> func) where T: BaseClass, new()
(
return func(new T());
)
And you call it like this:
var result = ExecuteMethod<ClassA>(a => a.Function1);
The second solution
This might be more suitable for your needs:
You will need to create two dictionaries and populate them, like this:
private Dictionary<int, Func<ParentClass>> constructors = new Dictionary<int, Func<ParentClass>>()
{
{1, () => new ClassA()},
{2, () => new ClassB()}
// more of the same
};
private Dictionary<int, Func<ParentClass, string>> methods = new Dictionary<int, Func<ParentClass, string>>()
{
{1, i => i.function1},
{2, i => i.function2}
// more of the same
};
Then your method can still take two ints and return a string:
string DoSomething(int classType, int function)
{
var instance = constructors[classType].Invoke();
return methods[function].Invoke(instance);
}
Please note that the code is written directly here and not tested, so I might have missed a thing or two, but this is the general idea.
I did some changes to your original code, I changed the input parameters to strings, assuming you can directly take names as input. And then instantiating using the first method and invoking using the second. I have added an overload if you want to continue to use the Enum.
string selectedClass;
string selectedFunction;
public object GetClassInstanceFromName(string name)
{
object type = Type.GetType($"{this.GetType().Namespace}.{name}";
return Activator.CreateInstance((Type)type);
}
public string InVokefunctionByName(object instance,string methName)
{
return instance.GetType().GetMethod(methName).Invoke(instance, null) as string;
}
//Overload if you want to continue to use your enum
public object GetClassInstanceFromName(ClassTypes name)
{
return
Activator.CreateInstance(Assembly.GetExecutingAssembly().FullName,
"class" +name.ToString());
}
private void Test()
{
object a = GetClassInstanceFromName(selectedClass);
Console.WriteLine(InVokefunctionByName(a, selectedFunction));
Console.ReadKey();
}
Also switching to a better design will always be recommended way.

C#, Generics, Type and NHibernate

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.

List method creation

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);

Strongly typed object from string type name (C#)

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.

IList<IWhatever> as a method parameter

I have two IList<ICat> and I'm trying to create a method which takes an IList<ICat> and does some work. I'm having problems trying to pass either an IList<PussyCat> or IList<OtherCat> to it, both PussyCat and OtherCat implement ICat.
I've tried:
List<PussyCat> cats = ...
DoWork((IList<ICat>)cats);
and just
DoWork(cats);
But neither compile. Any ideas?
C# generics are invariant. It means List<string> is not a List<object>.
C# 4.0 introduces safe covariance/contravariance but still, you wouldn't be able to pass List<string> as List<object>. The reason is:
List<string> x = new List<string>();
List<object> o = x; // assume this statement is valid
o.Add(5); // Adding an integer to a list of strings. Unsafe. Will throw.
Arrays, on the other hand are covariant. You can pass a string[] to a method that expects object[].
There are two alternatives:
Make your method like this:
public void DoWork< T > (IList< T > cats_) where T : ICat
{
//Do work;
}
The other possibility is to have a method like
public void DoWork(IList< ICat > cats_)
{
//Do work;
}
and call it in the following manner:
{
//....Assuming: IList<PussyCat> iListOfPussyCats
List<PussyCat> pussyCats = new List<PussyCats>(iListOfPussyCats);
DoWork(pussyCats.ConvertAll<ICat>( c => c as ICat);
}
If the method doesn't truly require direct indexing (IList<T>) and doesn't require adding/removing items (ICollection<T>), then pass an IEnumerable<T>. The Cast<T>() extension methods allow casting any IList of [insert ICat-derived type] to be passed as an IEnumerable<ICat>.
Till C# 4.0 arrives which has support for co and contra variance you might be able to get away with something like this:
public void DoWork(IEnumerable<ICat> cats)
{
//do something
}
List<PussyCat> pussyCats = new List<PussyCat>;
List<OtherCat> otherCats = new List<OtherCat>;
DoWork(pussyCats.OfType<ICat>);
DoWork(otherCats.OfType<ICat>);

Categories