Dilemma in calling constructor of generic class - c#

I have this generic singleton that looks like this:
public class Cache<T>
{
private Dictionary<Guid, T> cachedBlocks;
// Constructors and stuff, to mention this is a singleton
public T GetCache(Guid id)
{
if (!cachedBlocks.ContainsKey(id))
cachedBlocks.Add(id, LoadFromSharePoint(id))
return cachedBlocks[id];
}
public T LoadFromSharePoint(Guid id)
{
return new T(id) // Here is the problem.
}
}
The error message is:
Cannot create an instance of type T because it does not have the new() constraint.
I have to mention that I must pass that id parameter, and there is no other way to do so. Any ideas on how to solve this would be highly appreciated.

Normally you would constrain the type T to a type that has a default constructor and call that. Then you'd have to add a method or property to be able to provide the value of id to the instance.
public static T LoadFromSharePoint<T>(Guid id)
where T : new() // <-- Constrain to types with a default constructor
{
T value = new T();
value.ID = id;
return value;
}
Alternatively since you specify that you have to provide the id parameter through the constructor, you can invoke a parameterized constructor using reflection. You must be sure the type defines the constructor you want to invoke. You cannot constrain the generic type T to types that have a particular constructor other than the default constructor. (E.g. where T : new(Guid) does not work.)
For example, I know there is a constructor new List<string>(int capacity) on List<T>, which can be invoked like this:
var type = typeof(List<String>);
object list = Activator.CreateInstance(type, /* capacity */ 20);
Of course, you might want to do some casting (to T) afterwards.

To do this you should specify what T is. Your Cache<T> can hold anything? Tiger, Fridge and int as well? That is not a sound design. You should constrain it. You need an instance of T which will take a Guid to construct the instance. That's not a generic T. Its a very specific T. Change your code to:
public class Cache<T> where T : Cacheable, new()
{
private Dictionary<Guid, T> cachedBlocks;
// Constructors and stuff, to mention this is a singleton
public T GetCache(Guid id)
{
if (!cachedBlocks.ContainsKey(id))
cachedBlocks.Add(id, LoadFromSharePoint(id))
return cachedBlocks[id];
//you're first checking for presence, and then adding to it
//which does the same checking again, and then returns the
//value of key again which will have to see for it again.
//Instead if its ok you can directly return
//return cachedBlocks[id] = LoadFromSharePoint(id);
//if your LoadFromSharePoint is not that expensive.
//mind you this is little different from your original
//approach as to what it does.
}
public T LoadFromSharePoint(Guid id)
{
return new T { Key = id }; // Here is no more problem.
}
}
public interface Cacheable
{
Guid Key { get; set; }
}
Now derive all the cacheables (whatever Ts that you will pass it for Cache<T>) from the interface Cacheable.

In order to use the constructor of a Generic Type without any constraint, and within the class, the syntax where T : class, new() needs to be used
This enables to change values of attributes (fields) - not only get/set properties) at runtime depending the target class used
First, declaring the generic class:
public class Foo<T> where T : class, new()
{
public T oneEmptyElement()
{
return new T();
}
public T setAttribute(string attributeName, string attributeValue)
{
T objT = new T();
System.Reflection.FieldInfo fld = typeof(T).GetField(attributeName);
if (fld != null)
{
fld.SetValue(objT, attributeValue);
}
return objT;
}
public List<T> listOfTwoEmptyElements()
{
List<T> aList = new List<T>();
aList.Add(new T());
aList.Add(new T());
return aList;
}
}
Declare then a potential target class:
public class Book
{
public int name;
}
And finally the call can be done like this:
Foo<Book> fooObj = new Foo<Book>();
Book aBook = fooObj.oneEmptyElement();
aBook.name = "Emma";
Book anotherBook = fooObj.setAttribute("name", "John");
List<Book> aListOfBooks = fooObj.listOfTwoEmptyElements();
aListOfBooks[0].name = "Mike";
aListOfBooks[1].name = "Angelina";
Console.WriteLine(aBook.name); //Output Emma
Console.WriteLine(anotherBook.name); //Output John
Console.WriteLine(aListOfBooks[0].name); // Output Mike
Console.WriteLine(aListOfBooks[1].name); // Output Angelina

Related

Resolving generic method parameters in C#

I have a method that is overloaded 3 times with the exact same functionality, the only change is one parameter which is a list of a concrete type.
private void _doWork(string name, List<TargetItem> members)
{
foreach(var member in members)
{
_doExtraWork(member.TimeToWork);
}
}
private void _doWork(string name, List<NonTargetItem> members)
{
foreach(var member in members)
{
_doExtraWork(member.TimeToWork);
}
}
Thing to know here is the 2 classes in the lists are coming from a WSDL definition. The operation in the iteration is on shared members as they derive from the same base class, however this inheritance is abstracted in the WSDL.
I have tried to do something like this -
private void _doWork<T>(string name, List<T> members)
{
var commonList = new List<>(); /// what type should I use here?
if(typeof (T) == typeof(TargetItem))
{
commonList = members; // assume equal to means copying members to commonList with type conversion
}
if(typeof (T) == typeof(NonTargetItem))
{
commonList = members;
}
foreach(var member in commonList)
{
_doExtraWork(member.TimeToWork);
}
}
Is this the right way to approach the problem and refactor this common code, or am I missing something here?
you can do something like this
private static void _doWork<T>(string name, T members) where T : IEnumerable
{
foreach(var member in members)
{
_doExtraWork(member.TimeToWork);
}
}
In your Calling Code
_doWork("sdfsd", new List<TargetItem>()); // here just as example I am passing new instance
_doWork("sdfsd", new List<NonTargetItem>()); // here just as example I am passing new instance
As the List<T> is of type IEnumerable<T> which in turn is of type IEnumerable. You can add IEnumerable generic constaints in your generic functions. In this way, you do not have to do type checking in your generic functions.
If you want to implement single doExtraWork method then you need to have CommonType for both TargetItem and NonTargetItem. you can solve this using Adapter Pattern like below
Interface IItem
{
int TimeToWorkAdapt {get;}
}
//Now create a wrapper class for TargetItem and NonTargetItem
Class TargetItemAdapt : TargetItem,IItem
{
public int TimeToWorkAdapt
{
get { base.TimeToWork;}
}
}
Class NonTargetItemAdapt : NonTargetItem,IItem
{
public int TimeToWorkAdapt
{
get { base.TimeToWork;}
}
}
// write a generic function which wrap calls to your do extra work method but with generic constriants to interface
private static void _doExtraWork<T>(T members) where T : IItem
{
_doExtraWork(member.TimeToWorkAdapt);
}
// In your Main program...now use our wrapper classes
_doWork("sdfsd", new List<TargetItemAdapt>()); // here just as example I am passing new instance
_doWork("sdfsd", new List<NonTargetItemAdapt>()); // here just as example I am passing new instance
I chose to downcast from the caller
_doWork("Target", Object.TargetItems.ToList<BaseClass>());
_doWork("NonTarget", Object.NonTargetItems.ToList<BaseClass>());

Return concrete type in abstract class

We have an abstract class BaseClass (note generic arg!) with a method called me.
Me returns this.
If we use Me in the concrete classes we will get a return type object.
Then we have to cast the result of Me to the type we originally are working with.
How can we achieve that Me returns the actual type of this? In this example type A?
public abstract class BaseClass<TIdentifier>{
public virtual object Me{ get { return this; } }
}
public class A: BaseClass<long>
{
}
public class B: BaseClass<long>
{
}
public class controller{
public void SomeMethod(){
var a = new A();
var b = new B();
var aObject = a.Me; // this will be of type object
var aObjectCasted = (A)aObject; // cast to original
// How I want it
var aConcrete = a.Me; // this returns type a
}
}
Update
Since some people really, desperately (wink:-)) wish to understand what I'm actually trying to do.
With NHibernate we are doing this:
var result = Session.Get<A>(idToLookUp);
In some cases it happens that result isn't of type A but is of type AProxy, due to laze loading etc. Now if we want to cast result to something else: we will get an invalidcastexception because the actual type of result isn't A but AProxy. And that type can't be casted. We can only cast type A to the other type.
A workaround for this is described here: http://sessionfactory.blogspot.be/2010/08/hacking-lazy-loaded-inheritance.html. That's where the Me property in the above examples comes in.
So to get result of type A and not of type AProxy we now have to do this:
var result = (A)Session.Get<A>(idToLookUp).Me;
Note we have to cast me back to type A if we want to get to read and know the property of result.
My question: can we get rid of the casting and adjust the Me property so we instantly return the concrete type?
Hope it's clear now.
You could use an interface on your derived classes:
public interface IStrongTypedMe<T>
{
T Me();
}
Your derived classes would become:
public class A: BaseClass<long>, IStrongTypedMe<A>
{
public new A Me()
{
return base.Me() as A;
}
}
This is assuming you can change A, of course.
Update:
I understand the issue now (only had time to read the linked article now).
Try using an extension method to do the casting for you like this:
public static TReturnType As<TReturnType,TIdentifier>(this BaseClass<TIdentifier> proxyObject)
where TReturnType : class
{
return proxyObject.Me as TReturnType;
}
And you'd use it like:
var result = Session.Get<A>(idToLookUp).As<A,long>();
No changes to A or B required.
You can change the return type of this property to the definition of parent class
public abstract class BaseClass<TIdentifier>
{
public virtual BaseClass<TIdentifier> Me{ get { return this; } }
}
If you want to return exactly the same class you can make some workaround by adding the result type in the generic type parameter
public abstract class BaseClass<TIdentifier, TMe>
where TMe : BaseClass<TIdentifier, TMe>, new()
{
public virtual TMe Me { get { return (TMe)this; } }
}
public class A : BaseClass<long, A>
{
}
Unfortunately, C#, unlike Java, does not support return type covariance. Otherwise you could just override the property Me in the subclasses like this to get what you want:
public abstract class BaseClass<TIdentifier> {
public virtual object Me { get { return this; } }
}
public class A: BaseClass<long>
{
public override A Me { get { return this; } } // wont work in C#
}
public class B: BaseClass<long>
{
public override B Me { get { return this; } } // wont work in C#
}
Mikhail Neofitov provides a good workaround though.
In order to do something like this:
var aObject = A.Me();
Me will need to be a static method.
A static method doesn't have a this.
If your not using a static method, you have the this - otherwise how are you willing to call the class method? You just need to cast it to the correct type.
Update Due To Edit:
You have this code:
var a = new A();
var aObject = a.Me;
Now what are you expecting here?
You have a which is from type A.
By using var you can't have multiple different return types from the Me geter.
The problem seems to be the implicit definition of the variable using var. When you are using var in this case, the compiler cannot determine the correct type for aObject in the editor. So take the following code for example:
public abstract class BaseClass<TIdentifier>
{
public virtual object Me {get {return this;} }
}
public class A : BaseClass<TIdentifier>
{
public int X
{
get {return 1;}
}
}
public class B : BaseClass<TIdentifier>
{
}
public class controller{
public void SomeMethod(){
var a = new A();
var b = new B();
var aObject = a.Me;
var aObjectCasted = (A)aObject;
// the environment cannot determine the correct type for aObject
// without compiling and running. At this time in the editor,
// this will be recognized as a type object. It will not
// understand aObject.X and will not compile
Console.WriteLine(aObject.X);
// During run-time, this will work. aObject will be defined as type A
Console.WriteLine(aObject.GetType().GetProperty("X").GetValue(aObject));
// this will output A for the type
Console.WriteLine(aObject.GetType());
}
}
Without being able to modify A and B, using the GetProperty, GetMethod, etc. methods on the implicitly defined variable seems like it will be your only hope.
Update:
You can reference this to see the types of calls you can make on a Type object. It seems like you will have to do this more dynamically that desired to achieve the functionality you want. The object will not be defined correctly before compiling if trying to do it implicitly.
var aConcrete = a.Me; in your code will indeed return yield a type A for aConcrete at compile time, but not in the editor.
From MSDN: "It is important to understand that the var keyword does not mean "variant" and does not indicate that the variable is loosely typed, or late-bound. It just means that the compiler determines and assigns the most appropriate type."

How to instantiate Generic class object?

I am trying to convert the following c# code into java
abstract class BaseProcessor<T> where T : new()
{
public T Process(HtmlDocument html)
{
T data = new T();
Type type = data.GetType();
BindingFlags flags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.SetProperty;
PropertyInfo[] properties = type.GetProperties(flags);
foreach (PropertyInfo property in properties)
{
string value = "test";
type.InvokeMember(property.Name, flags, Type.DefaultBinder, data, new object[] { value });
}
}
}
So i have done upto
public class BaseProcessor<T>
{
public T Process(String m_doc)
{
T data = (T) new BaseProcessor<T>(); // this is not working
Document doc = Jsoup.parse(m_doc);
return data;
}
}
When i instantiate the data object its not acquiring the properties of the Generic class at runtime
let say for example when i hit the code its not getting properties of DecodeModel class
IDocProcessor<DecodeModel> p = new DecodeThisProcessor();
return p.Process(doc);
public interface IDocProcessor<T>
{
T Process(String webresponse);
}
public class DecodeThisProcessor extends BaseProcessor<DecodeModel> implements IDocProcessor<DecodeModel>
{
public void setup();
}
So please help me what will be the right syntax to instantiate generic object data
You cannot instantiate generics. The reason is that the type is not available at run-time, but actually replaced with Object by the compiler. So
T data = new T(); // Not valid in Java for a generics T!
would in fact be:
Object data = new Object(); // Obviously not the desired result
Read the Java Generics Tutorial wrt. to "type erasure" for details.
You will need to employ the factory pattern.
T data = factory.make();
where
public interface Factory<T> {
T make();
}
needs to be implemented and passed to the constructor. To make this work, you need a factory that knows how to instantiate the desired class!
A (rather obvious) variant is to put the factory method into your - abstract - class.
public abstract class BaseProcessor<T>
{
protected abstract T makeProcessor();
public T Process(String m_doc)
{
T data = makeProcessor(); // this is now working!
and when extending BaseProcessor implement it for the actual final type.
Tough luck; in Java the whole of Generics is strictly a compile-time artifact and the instantiation of the type parameters doesn't exist in the runtime. The usual workaround is to pass an instance of Class as a marker, which will allow you to reflectively create an object of that type. This is fraught with many pitfalls, but is the best you can get in Java.
You can do this:
public class BaseProcessor<T>
{
private Class<T> clazz;
public BaseProcessor(Class<T> clazz)
{
this.clazz = clazz;
}
public T Process(String m_doc)
{
T data = clazz.newInstance()
Document doc = Jsoup.parse(m_doc);
return data;
}
}
Hint: Make sure that T has a no-arg constructor.

Cannot provide arguments when creating an instance of generic type

I have an object that I want to have read only after it is created... namely because the properties in the constructor must be used in GetHashCode, and therefore can't change once created.
I this is one of many classes that are readonly:
public class AccountLabel
{
private string result;
public AccountLabel(string result)
{
// TODO: Complete member initialization
this.result = result;
}
public string JSONRPCData { get { return this.result; } }
}
I have a generic result class like this
public class JsonResult<T> where T : JObject, new()
{
private T bhash;
private string p;
private JsonErrorResponse error;
private int _id;
private Newtonsoft.Json.Linq.JObject ret;
public JsonResult(Newtonsoft.Json.Linq.JObject ret)
{
this.ret = ret;
var tempError = ret["error"];
var tempid = ret["id"];
JsonErrorResponse error = new JsonErrorResponse(tempError);
this.error = error;
this._id = 1;
var tempresult = ret["result"];
T someResult = new T(tempresult); // <--- here is my problem
}
My problem is that I want to pass an object into T's constructor but can't. When I type this the compiler tells me Cannot provide arguments when creating an instance of variable type
What is the best way to work around this situation?
Should I have an Interface that I can call that will update the property?
Will that previous Interface break encapsulation or allow changes to be made to my object?
How else should I approach this?
You can remove the new type constraint, and use Activator.CreateInstance instead.
Instead of this
T someResult = new T(tempresult);
write this:
T someResult = (T)Activator.CreateInstance(
typeof(T)
, new object[] { tempresult }
);
This is likely to be somewhat slower because of going through reflection, and the static checks by the compiler would not be performed. However, considering your scenario, it does not look like either of these would present a significant problem.
You could pass in a factory delegate to the constructor of JSonResult<T>:
public class JsonResult<T> where T : JObject
{
public JsonResult(Newtonsoft.Json.Linq.JObject ret, Func<object, T> factory)
{
var tempresult = ret["result"];
T someResult = factory(tempresult);
}
}
object in Func<object, T> could be replaced with whatever the type of tempResult actually is.

Generic Lookup Method

I'm wanting to create a generic lookup method to where you specify a type of object and some other identifying parameters and the method returns an object of that type. Is this possible?
I'm thinking something like this.
public T GetObjectOfType(Guid ID, typeof(T Class))
{
//lookup this object and return it as type safe
}
I know this just won't work but i hope it explains the concept
You can use a generic method for this:
public T GetObjectOfType<T>(Guid id) where T: class, new()
{
if (id == FooGuid) //some known identifier
{
T t= new T(); //create new or look up existing object here
//set some other properties based on id?
return t;
}
return null;
}
If all you want is create an instance of a specific type you do not need the additional id parameter, I assume you want to set some properties etc. based on the id. Also your class must provide a default constructor, hence the new() constraint.
Typically factory methods do not take the type of object to create. They return a type that implements some common interface and the concrete, underlying type is dependent on some argument, typically an enumerated value. A simple example:
interface Whatever
{
void SomeMethod();
}
class A : Whatever { public void Whatever() { } }
class B : Whatever { public void Whatever() { } }
enum WhateverType { TypeA, TypeB }
public void GetWhatever( WhateverType type )
{
switch( type )
{
case WhateverType.TypeA:
return new A();
break;
case WhateverType.TypeB:
return new B();
break;
default:
Debug.Assert( false );
}
}
There you have type safety. I'm not sure how you would implement something like that with generics as you need to supply the generic argument at compile time.

Categories