How to use generic for code reusability - c#

I want to use Generic for reusability.
Code to be applied are listed below.
pubic Class Test < T >
{
T item;
...
public void set(T item)
{
this.item = item;
// if (T type == int) {...}
// if (T type == string) {...}
abc();
}
private void abc()
{
...
}
}
Question1. I heard that using attribute is best solution in this situation.
How do I implement this? Please, Tell me if you have any example.
(Type will be added continually)
Question2. Is using Generic best solution about above example??
Thanks.

You should avoid checking for particular types inside generic methods and classes. You could make set a template method and then override the type-specific behaviour inside subclasses which specify the type T e.g.
public class Test<T> {
public void Set(T item) {
this.item = item;
this.OnSet(item);
abc();
}
protected virtual void OnSet(T item) { }
}
public class IntTest : Test<int> {
protected override void OnSet(int item) { ... }
}
public class StringTest : Test<string> {
protected override void OnSet(string item) { ... }
}

I think you're looking for:
if (item is int) else if(item is string)...
Whether it's the best approach or not, I leave up to others.

Related

List<> of specific class types

Say that I have a series of classes:
abstract class MyClass { }
class MyFirstClass : MyClass { }
class MySecondClass : MyClass { }
class MyThirdClass : MyClass { }
I want to do something based on a configurable list of these derived class types, so I want to store the chosen class's Types in a list. I know I could create a List<Type>, but I could theoretically add any class to that list. On the other hand, a List<MyClass> would be a list of instances of these classes, rather than a list of the types themselves. I could also create an enum with one value that corresponds to each derived type, and have a factory method to create the correct one as needed, but that's at least two more places I'd have to update when I added MyFourthClass.
Is there a way to do something like new List<typeof(MyClass)>() = new[] { typeof(MyFirstClass), typeof(MyThirdClass)}? Does the very fact I'm asking this question imply a problem with my design?
What you want is a generic list of types (List<Type>) but like you said, you can insert any type there. The solution I can give you is to implement your own List of types from MyClass, for instance:
class TypeMyClassList : IList<Type>
{
private readonly List<Type> _list = new List<Type>();
private bool CheckType(Type type)
{
return type.IsSubclassOf(typeof (MyClass)) || typeof (MyClass) == type;
}
public IEnumerator<Type> GetEnumerator()
{
return _list.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public void Add(Type item)
{
if (CheckType(item))
_list.Add(item);
else
throw new InvalidOperationException("You can't add other types than derived from A");
}
public void Clear()
{
_list.Clear();
}
public bool Contains(Type item)
{
return _list.Contains(item);
}
public void CopyTo(Type[] array, int arrayIndex)
{
_list.CopyTo(array, arrayIndex);
}
public bool Remove(Type item)
{
return _list.Remove(item);
}
public int Count
{
get { return _list.Count; }
}
public bool IsReadOnly { get { return false; } }
public int IndexOf(Type item)
{
return _list.IndexOf(item);
}
public void Insert(int index, Type item)
{
if (!CheckType(item))
throw new InvalidOperationException("You can't insert other types than derived from A");
_list.Add(item);
}
public void RemoveAt(int index)
{
_list.RemoveAt(index);
}
public Type this[int index]
{
get
{
return _list[index];
}
set
{
Insert(index, value);
}
}
}
Then you could do thinks like this that you want:
var typeMyClassList = new TypeMyClassList
{
typeof(MyClass),
typeof(MyClassA),
typeof(MyClassB)
};
The bad thing is that it will allows to do this in compilance time (the error will be raised on runtime):
var typeMyClassList = new TypeMyClassList
{
typeof(MyClass),
typeof(MyClassA),
typeof(MyClassB),
typeof(string)
};
There's no way to do this with static, compile-time type checking. Your best bet is to go with a solution like Raul OtaƱo's in which you do your checks at runtime.
Why can't you do this? The reason is that C# lacks static metaclass types. A metaclass is the class of a class. In other words, the instances of a metaclass are themselves classes. If C# had metaclasses, you could say something like IList<MyClassMeta> (or perhaps the syntax would be IList<meta MyClass> and the compiler would only allow you to pass MyClass (or its subclasses) as "instances", e.g.,
IList<meta MyClass> list;
list.Add(MyClass);
I've been wanting this functionality for a long time, but I don't expect it any time soon.

Is it possible to use a delegate or generic for any void method?

I am trying to write an exception handler class that converts from types of EF exceptions to HttpStatusCodes.
I know how to handle the catching and sending the message to the ApiController.
public class ExceptionConverter : IExceptionConverter
{
//need the parameter
public HttpStatusCode Convert()
{
try
{
//call the void repository method here
}
catch (Exception exception)
{
if (exception is ObjectNotFoundException)
return HttpStatusCode.NotFound;
if (exception is InvalidOperationException)
return HttpStatusCode.BadRequest;
}
return HttpStatusCode.OK;
}
}
I am wondering if there is a way to write a Delagate or Generic method that could call my void repository methods.
I was thinking I could use an interface with the methods I use in my conversion
public interface IHandleCrudOperations
{
//All of these methods need to be able to take in many different parameters
//They will always need a parameter though
void Remove();
void Add();
void Edit();
void Clone();
}
As you can see I would need to be able to pass in a slew of different parameters based on the repository method in question:
//userRepository
public void Remove(int userKey)
{
//stuff
}
//groupRepository
public void Remove(string groupName)
{
//stuff
}
//someOtherRepository
public void Remove(RemoveSomethingRequest request)
{
//stuff
}
I considered using a generic methods for this:
public interface IHandleCrudOperations
{
//All of these methods need to be able to take in many different parameters
//They will always need a parameter though
void Remove<T>(T item);
void Add<T>(T item);
void Edit<T>(T item);
void Clone<T>(T item);
}
Now the implementation gets difficult:
//userRepository
public void Remove<T>(T item)
{
//SERIOUS code smell here
var userKey = (int)(object)item
_context.Users.FirstOrDefault(x => x.UserKey == userKey);
//stuff
}
//groupRepository
public void Remove<T>(T item)
{
//SERIOUS code smell here
var groupName = (string)(object)item
//stuff
}
//someOtherRepository
public void Remove<T>(T item)
{
//SERIOUS code smell here
var request = (RemoveSomethingRequest)(object)item
//stuff
}
That has many bad flaws, readability, abusing generics, generally just bad, etc....
So, since all of the methods for this operation return void:
Is this possible with Delegates?
Is there another way to handle this?
IT looks to me like you have different types of keys: Users have an int key, and Groups have a string key. So I'd make a generic interface whose methods don't have type parameters, like this:
interface IRepository<TItem, TKey>
{
void RemoveItem(TItem item);
void RemoveByKey(TKey key);
void RemoveByName(string name);
}
The implementation should be clear from that, but if it isn't leave a comment.
EDIT: You could also do this, but only if TKey and TItem are never the same, and are never string:
interface IRepository<TItem, TKey>
{
void Remove(TItem item);
void Remove(TKey key);
void Remove(string name);
}
You could move the generic parameter T to the interface itself:
public interface IHandleCrudOperations<TKey, T>
{
void Remove(TKey item);
void Add(T item);
void Edit(T item);
void Clone(T item);
}
public class UserRepository : IHandleCrudOperations<int, User>
{
public void Remove(int userKey)
{
_context.Users.FirstOrDefault(x => x.UserKey == userKey);
//stuff
}
public void Add(User user)
{
}
}

Finding out type of a generic class

Lets say I have a generic class:
class Foo {
// protected Type t;
// public void SetT(string strval) {
// ((Foo<t>)this).Set(strval);
// }
}
class Foo<T> : Foo {
private T val;
public void Set(string strval) {
if (this is Foo<float>) {
this.val = float.Parse(strval);
} else if (this is Foo<int>) {
this.val = int.Parse(strval);
}
}
}
Now I create an object and put it in an ArrayList:
ArrayList a = new ArrayList();
a.Append(new Foo<float>);
And then I forget the type of Foo<>. Now, how do I Set? I tried the obvious candidates:
(Foo)a[0].Set("5.0");
(Foo<a[0].GetType()>)a[0].Set("5.0");
but those failed.
Is there a way I can call that Set method without explicitly knowing the type of Foo<>?
If not, can I somehow save type of Foo into Foo.t, and then uncomment and use Foo.SetT?
Ah, generics. Very nice tool if you know how to use them :-)
Regards,
dijxtra
One way is to make your generic Foo class implement an interface:
interface IFoo {
void Set(string strval);
}
class Foo<T> : IFoo {
private T val;
public void Set(string strval) {
...
}
}
Then you can cast to IFoo and call Set():
((IFoo)a[0]).Set("5.0");
There's absolutely no reason to be using generics here. Generics are intended to be used when the type of operations you will be performing are generic. In other words, they are independent of the type(s) on which they are performed. You are doing the opposite: the operation will be different depending on the types.
Given that, you should remove the generic parameter, make Set() and Foo abstract, and derive appropriate classes to handle the different types:
abstract class Foo
{
public abstract void Set(string value);
}
class FooDouble : Foo
{
double val;
public override void Set(string value)
{
this.val = double.Parse(value);
}
}
// Etc.
Then, you should be storing your Foos in a List<T>:
List<Foo> fooList = new List<Foo>();
fooList.Add(new FooDouble());
Later, you can say this:
fooList[0].Set("5.0");
And it will just work! No need to remember!
You want to override the implementation of Set in the derived classes.
class Foo {
public virtual void Set(string val);
}
class Foo<T> : Foo {
public override void Set(string val);
}
In addition to what Jimmy pointed out for your base class, you could use a generic collection instead of an ArrayList and make use of a type converter:
public interface IFoo
{
void Set(string value);
}
public class Foo<T> : IFoo
{
private T val;
public void Set(string value)
{
var typeConverter = TypeDescriptor.GetConverter(typeof(T));
if(typeConverter.CanConvertFrom(typeof(string)))
{
val = (T)typeConverter.ConvertFromString(value);
}
else
{
throw new InvalidOperationException();
}
}
}
The above will work with either your ArrayList:
ArrayList a = new ArrayList();
a.Append(new Foo<float>());
((IFoo)a[0]).Set("123.4");
Or with a typed collection:
List<IFoo> list = new List<IFoo>();
list.Add(new Foo<float>());
list[0].Set("123.4");
As an added bonus, you don't need to have an if statement in your Set method and try to account for all possible types.
If you want to know the type parameter that was used in you generic, use the GetGenericArguments method.
class Foo<T> {
int input_as_int;
float input_as_float;
public void Set(string strval) {
if (this.GetType().GetGenericArguments().First() == typeof(float)) {
this.input_as_float = float.Parse(strval);
} else if (this.GetType().GetGenericArguments().First() == typeof(int)) {
this.input_as_int = int.Parse(strval);
}
// Else .. throw an exception? return default value? return 0? what makes sense to your application
}
or alternately if you could by pass the Interface entirely and pass the input string in the constructor.
public class Foo<T>
{
public Foo (string input)
{
var typeConverter = TypeDescriptor.GetConverter(typeof(T));
if (typeConverter.CanConvertFrom(typeof(string)))
{
Value = (T)typeConverter.ConvertFromString(input);
}
else
{
throw new InvalidOperationException();
}
}
public T Value { get; set;
}
}
then you can just use it like so.
var test = new List<int> Foo ("3");
using System;
using System.Collections;
using System.Collections.Generic;
class Foo {
}
class Foo<T> : Foo {
private T val;
public void Set(string strval) {
var _type = typeof(T);
val = (T)(_type.InvokeMember("Parse", System.Reflection.BindingFlags.InvokeMethod, null, null, new Object[] { strval }));
}
override public string ToString(){
return String.Format("{0}", val);
}
}
class Sample {
static void Main(string[] args){
ArrayList a = new ArrayList();
a.Add(new Foo<float>());
a.Add(new Foo<int>());
dynamic ax = a[0];
ax.Set("5.5");
ax = a[1];
ax.Set("55");
//EDIT
//But I may have to set the float value to Foo <int> If you forgot
// ((Foo<float>)a[0]).Set("5.5");
// ((Foo<int>)a[1]).Set("55");
Console.WriteLine("{0},{1}", a[0], a[1]);
}
}

Referencing a derived type inside itself

I have something link this:
public abstract class Wrapper<T, TWrapped>: where TWrapped : Wrapper<T, TWrapped>
{
protected T baseObject;
protected ICollection<T> baseList;
protected ICollection<TWrapped> wrappedList;
public Wrapper (T base, ICollection<T> baseList, ICollection<TWrapped> wrappedList) { }
}
Then when I derive from it I need to to something like:
public class Base { }
public class Sample: Wrapper<Base, Sample> { }
Is there a way to remove the TWrapped and create a reference to the derived type? I tried using ICollection<Wrapped<T>> but then I remember that there is no covariance in ICollection.
EDIT: Clarifications, what I want with this wrapper is provide removal funcionality (and some other things) within the object (I can't change the base object so I need a wrapper to give this funcionality and manipulate it). This abstract class will have methods like this:
void Remove()
{
while(this.baseList.Remove(baseObject));
this.baseList = null;
while(this.wrappedList.Remove((TWrapped)this));
this.wrappedList = null;
}
I end up changing the logic of how I'm going to make the lists sync and allow Items to remove themselves. I created a new class to hold a collection of the wrapped items:
public interface IWrapper<TModel>
{
TModel Model { get; }
}
public class WrapperCollection<TWrapper, TModel> : ObservableCollection<TWrapper> where TWrapper : IWrapper<TModel>
{
protected IList<TModel> modelList;
public ReadOnlyObservableCollection<TWrapper> AsReadOnly { get; private set; }
protected WrapperCollection(IList<TModel> modelList)
{
this.modelList = modelList;
AsReadOnly = new ReadOnlyObservableCollection<TWrapper>(this);
}
public WrapperCollection(IList<TModel> modelList, Func<TModel, TWrapper> newWrapper)
:this(modelList)
{
foreach (TModel model in modelList)
this.Items.Add(newWrapper(model));
}
public WrapperCollection(IList<TModel> modelList, Func<TModel, WrapperCollection<TWrapper, TModel>, TWrapper> newWrapper)
: this(modelList)
{
foreach (TModel model in modelList)
this.Items.Add(newWrapper(model, this));
}
protected override void ClearItems()
{
modelList.Clear();
base.ClearItems();
}
protected override void InsertItem(int index, TWrapper item)
{
modelList.Insert(index, item.Model);
base.InsertItem(index, item);
}
protected override void RemoveItem(int index)
{
modelList.RemoveAt(index);
base.RemoveItem(index);
}
protected override void SetItem(int index, TWrapper item)
{
modelList[index] = item.Model;
base.SetItem(index, item);
}
}
Using the sample class:
public class wrappedInt: IWrapper<int>
{
private WrapperCollection<wrappedInt, int> list;
public Model { get; private set; }
public wrappedInt(int source, WrapperCollection<wrappedInt, int> list)
{
this.Model = source;
this.list = list;
}
public void RemoveMe()
{
if (list != null)
{
list.Remove(this);
list = null;
}
}
}
Then I can instantiate a collection with new WrapperCollection<wrappedInt, int>(listOfInts, (model, parent) => new wrappedInt(model, parent));.

C# Casting a List<ObjBase> as List<Obj>

Why can I not cast a List<ObjBase> as List<Obj>? Why does the following not work:
internal class ObjBase
{
}
internal class Obj : ObjBase
{
}
internal class ObjManager
{
internal List<Obj> returnStuff()
{
return getSomeStuff() as List<Obj>;
}
private List<ObjBase> getSomeStuff()
{
return new List<ObjBase>();
}
}
Instead I have to do this:
internal class ObjBase
{
}
internal class Obj : ObjBase
{
}
internal class ObjManager
{
internal List<Obj> returnStuff()
{
List<ObjBase> returnedList = getSomeStuff();
List<Obj> listToReturn = new List<Obj>(returnedList.Count);
foreach (ObjBase currentBaseObject in returnedList)
{
listToReturn.Add(currentBaseObject as Obj);
}
return listToReturn;
}
private List<ObjBase> getSomeStuff()
{
return new List<ObjBase>();
}
}
I get the following error in Visual Studio 2008 (shortened for readability):
Cannot convert type 'List' to 'List' via a reference conversion, boxing conversion, unboxing conversion, wrapping conversion, or null type conversion
Thanks.
You can use Cast and ToList extension methods from System.Linq to have this in one line.
Instead of
internal List<Obj> returnStuff()
{
return getSomeStuff() as List<Obj>;
}
do this:
internal List<Obj> returnStuff()
{
return getSomeStuff().Cast<Obj>().ToList();
}
I can only describe the "problem" from a Java view, but from what little I know this aspect is the same in both C# and Java:
A List<ObjBase> is not a List<Obj>, because it could contain an ObjBase object which is not a Obj object.
The other way around a List<Obj> can not be cast to a List<ObjBase> because the former guarantees to accept an Add() call with a ObjBase argument, which the latter will not accept!
So to summarize: even though a Obj is-a ObjBase a List<Obj> is not a List<ObjBase>.
Please look at the following questions:
.NET Casting Generic List
Why does this generic cast fail?
Covariance my friend.
Look at http://blog.t-l-k.com/dot-net/2009/c-sharp-4-covariance-and-contravariance
list.ConvertAll looks tempting but has 1 big disadvantage: it will create a whole new list. This will impact performance and memory usage especially for big lists.
With a bit more effort you can create a wrapper list class that keeps the original list as an internal reference, and convert the items only when they are used.
Usage:
var x = new List<ObjBase>();
var y = x.CastList<ObjBase, Obj>(); // y is now an IList<Obj>
Code to add to your library:
public static class Extensions
{
public static IList<TTo> CastList<TFrom, TTo>(this IList<TFrom> list)
{
return new CastedList<TTo, TFrom>(list);
}
}
public class CastedList<TTo, TFrom> : IList<TTo>
{
public IList<TFrom> BaseList;
public CastedList(IList<TFrom> baseList)
{
BaseList = baseList;
}
// IEnumerable
IEnumerator IEnumerable.GetEnumerator() { return BaseList.GetEnumerator(); }
// IEnumerable<>
public IEnumerator<TTo> GetEnumerator() { return new CastedEnumerator<TTo, TFrom>(BaseList.GetEnumerator()); }
// ICollection
public int Count { get { return BaseList.Count; } }
public bool IsReadOnly { get { return BaseList.IsReadOnly; } }
public void Add(TTo item) { BaseList.Add((TFrom)(object)item); }
public void Clear() { BaseList.Clear(); }
public bool Contains(TTo item) { return BaseList.Contains((TFrom)(object)item); }
public void CopyTo(TTo[] array, int arrayIndex) { BaseList.CopyTo((TFrom[])(object)array, arrayIndex); }
public bool Remove(TTo item) { return BaseList.Remove((TFrom)(object)item); }
// IList
public TTo this[int index]
{
get { return (TTo)(object)BaseList[index]; }
set { BaseList[index] = (TFrom)(object)value; }
}
public int IndexOf(TTo item) { return BaseList.IndexOf((TFrom)(object)item); }
public void Insert(int index, TTo item) { BaseList.Insert(index, (TFrom)(object)item); }
public void RemoveAt(int index) { BaseList.RemoveAt(index); }
}
public class CastedEnumerator<TTo, TFrom> : IEnumerator<TTo>
{
public IEnumerator<TFrom> BaseEnumerator;
public CastedEnumerator(IEnumerator<TFrom> baseEnumerator)
{
BaseEnumerator = baseEnumerator;
}
// IDisposable
public void Dispose() { BaseEnumerator.Dispose(); }
// IEnumerator
object IEnumerator.Current { get { return BaseEnumerator.Current; } }
public bool MoveNext() { return BaseEnumerator.MoveNext(); }
public void Reset() { BaseEnumerator.Reset(); }
// IEnumerator<>
public TTo Current { get { return (TTo)(object)BaseEnumerator.Current; } }
}
I think you are misunderstanding the cast you are trying to do. You are thinking that you are changing the type of the object that is stored in the list, where you are actually trying to change the type of the list itself. It rather makes sense that you can't change the list itself as you have already populated it.
You might look at it as a list of a base class and then cast it when you are processing the list items, that would be my approach.
What is the purpose of this attempted cast?
C# currently does not support variance for generic types. From what I've read, this will change in 4.0.
See here for more information on variance in generics.
Linq has a ConvertAll method. so something like
list.ConvertAll<Obj>(objBase => objbase.ConvertTo(obj));
I'm not sure what else to suggest. I assume ObjBase is the base class, and if all ObjBase objects are Obj objects, i'm not sure why you would have the two objects in the first place. Perhaps i'm off the mark.
Edit: the list.Cast method would work better than the above, assuming they are castable to each other. Forgot about that until I read the other answers.
This is a major pain in C# - this is how generics were designed. List doesn't extend List, its just a completely different type. You can't cast or assign them to each other in any way, your only option is to copy one list to the other one.
Lazarus:
I thought that the compiler would realise that I wanted actions done on the objects of the list and not that I was trying to cast the list itself.
Some more information:
public abstract class ObjBase
{
}
internal interface IDatabaseObject
{
}
public class Obj : ObjBase, IDatabaseObject
{
}
internal interface IDatabaseObjectManager
{
List<ObjBase> getSomeStuff();
}
public class ObjManager : IObjManager
{
public List<Obj> returnStuff()
{
return getSomeStuff().Cast <Customer>().ToList<Customer>();
}
private List<ObjBase> getSomeStuff()
{
return new List<ObjBase>();
}
}
Now client code outside of this DLL can go:
ObjManager objM = new ObjManager();
List listOB = objM.returnStuff();
I'm going to be creating several Obj and ObjManager types for this part (O/RM) of the application.
(Darn comment block ran out of characters! :-)
Here is how I fixed the Conversion from a
list<SomeOtherObject>
to a
object
and then to a
List<object>
https://stackoverflow.com/a/16147909/2307326

Categories