I have an array which stores a dictionary of Types:
//The dictionary:
Dictionary<CacheKey,Type> TypeLookup;
//This is the enum:
public enum CacheKey
{
UserProfile,
CustomerQuickSearch,
CommissionConfiguration
}
I would like to use this Dictionary to declare a variable of type T
//instead of
T myvar;
//I want to dynamically declare myvar as:
//1)get the type for the cacheKey from the dictionary:
Type type = TypeLookup[cacheKey];
//2)declare myvar as the corresponding Type:
type myvar;
The background is that I am building a Distributed Caching infrastructure. I have a great little CachingProvider that allows you to update an item in the cache.
I would like to expose this method as a webservice so that all the servers in my farm can have their cache updated. But I would like to have only one method exposed as a webservice which then updates the corresponding item in cache.
This is the method I'm trying to expose:
public static void UpdateCacheEntryItem<T>(CacheKey cacheKey, int id)
{
//look up the cacheEntry in cache which is a dictionary.
Dictionary<int, T> cacheEntry = (Dictionary<int, T>) CacheRef[cacheKey.ToString()];
//call the corresponding method which knows how to hydrate that item and pass in the id.
cacheEntry[id] = (T)HydrateCacheEntryItemMethods[cacheKey].Invoke(id);
}
Things I've tried:
1) I tried exposing the method directly as a WCF service but of course that doesn't work because of the on the method.
2) I tried casting the Dictionary which would be find because I don't need to do anthing with the return value, I just need to update the item in cache. But that didn't work either. Error that I get: Unable to cast object of type 'System.Collections.Generic.Dictionary2[System.Int32,CachingPrototype.CustomerQuickSearch]' to type 'System.Collections.Generic.Dictionary2[System.Int32,System.Object]'.
Your comments were very helpful and helped me to answer my question. The solution I came up with is to simply wrap my WCF service method in a switch statement so that I could call the UpdateCacheEntryItem method with the correct type of T. Since there is no way to convert from Type to the generic T operator, this is the only option. Since I don't have that many types in Cache, this works pretty well. (The other solution would be to use an interface as stated below but that would not be as strongly typed as I would like.)
[OperationContract]
public void UpdateCacheEntryItem(CacheKey cacheKey, int id)
{
switch (cacheKey)
{
case CacheKey.UserProfile:
CacheProvider.UpdateCacheEntryItem<UserProfile>(cacheKey, id);
break;
case CacheKey.CommissionConfig:
CacheProvider.UpdateCacheEntryItem<CommissionConfig>(cacheKey, id);
break;
case CacheKey.CustomerQuickSearch:
CacheProvider.UpdateCacheEntryItem<CustomerQuickSearch>(cacheKey, id);
break;
default:
throw new Exception("Invalid CacheKey");
}
Thanks everyone for your help, you are brilliant!
The idea of "dynamically declaring a variable" is contrary to the whole point of there being a type as part of the declaration of a variable. The idea is that you can tell the compiler the type, so that it can check what you're doing. In this case you haven't expressed any information about the type at all. You might as well just declare myVar as being of type object; that's basically the same as saying "I know pretty much nothing about the value of myVar, except that it's a reference."
If you've got a common interface of course, that would be great - and then you could use the members of that interface safely (after creating/fetching an appropriate instance, of course). But otherwise, there's really not a lot you can do unless you know something about the type at compile time.
In C# 4 you could declare the variable to be of type dynamic which would make all the binding dynamic - basically you can do pretty much what you like with it, and it will all be resolved at execution time. I'd advise using static typing wherever you can though, so that errors can be caught at compile time instead.
It looks to me that an interface and some casting will solve your problem. Just have each of your cacheable classes implement an interface. Store items of this type in your dictionary. Presumably, CacheRef would be of type Dictionary<CacheKey,Dictionary<CacheKey,ICacheable>>. All that is left is to make sure that your cacheable classes implement the interface.
public interface ICacheable
{
}
public static void UpdateCacheEntryItem(CacheKey cacheKey, int id)
{
//look up the cacheEntry in cache which is a dictionary.
Dictionary<CacheKey,ICacheable> cacheEntry = CacheRef[cacheKey.ToString()];
//call the corresponding method which knows how to hydrate that item and pass in the id.
cacheEntry[id] = (ICacheable)HydrateCacheEntryItemMethods[cacheKey].Invoke(id);
}
Note that this isn't, like #Jon Skeet says in his comments to his answer, enforcing the type in your Dictionary. It's up to your code to make sure that you are putting the right kind of objects into each cache. I'd be comfortable with this as long as your hydration methods were covered by unit tests to ensure that when given a particular key, they always produce objects of the appropriate type.
Related
I'm not sure if this is possible and after lengthy research I haven't found something conclusive.
I am trying to dynamically create a new object (itself a new Type) from a dictionary. So say I have key and value that key and value will become a property that returns the value. Something that I can use like this:
Sample code
public T getObject(Dictionary<string, string> myDict)
{
// make a new object type with the keys and values of the dictionary.
// sample values in dictionary:
// id : 112345
// name: "greg"
// gender: "m"
// Eventually also make the interface?
}
// Somewhere else:
var myNewObject = helper.getObject();
// what is expected here is that when I type myNewObject.
// I get id, name, gender as suggestions
int id = myNewObject.Id;
What is important for me is to get intellisense out of it. So I can type object. and suggestions with all the keys will come out. This way I don't need to know the dictionary in advance in order to access the values (or else I would simply use the dictionary).
I have looked into Clay but it isn't clear to me how to use it to get intellisense as I want it. I also found this post about it.
Additionally I checked ImpromptuInterface but for both the documentation is poor or I can't figure it out.
If this is possible with Clay (it sure seems like it) how could I do it so It can work as a library on other projects that won't reference Clay?
If something is unclear or this is a duplicate don't hesitate to comment.
To allow IntelliSense to work, the resulting type must be known at compile-time. So at the time you're working with object, you must know its concrete type (or, at least, a type or interface as concrete as you need - having all the methods and properties you want to access).
It's hard to see what you're actually trying to do, but if you do know the type at compile-time, you can make your helper method generic:
public T GetObject<T>(Dictionary<...> dictionary)
This allows you to specify the type you're expecting at the call site:
var obj = GetObject<SomeType>(dictionary);
If this does not sound reasonable to you, you could also use an explicit cast:
var obj = (SomeType)helper.getObject();
If you don't know the concrete type, you'll at least need to have a common interface (or a base class) you can use. The runtime generated type would then be created to implement this interface. But you'll only ever be able to access the members that are known at compile time. How would the compiler know all the possible keys that could exist in your dictionary at runtime? You're trying to code against some kind of contract - so formalize that contract in an interface (for example), and make the runtime generated type implement this interface.
I've written a method with the signature:
private List<ClientItem> ConvertToClientItems(BaseCollection<object> serverItems)
I'm trying to call it in the following manner:
ConvertToClientItems(approvedSellers);
where approvedSellers is of type BaseCollection<Seller> - with Seller being a class that I don't have control over.
Shouldn't this be possible? Visual Studio is throwing an error at me saying that it cannot cast BaseCollection<seller> to BaseCollection<object>.
Well, imagine code that looks like this:
private List<ClientItem> ConvertToClientItems(BaseCollection<object> serverItems) {
serverItems.Add(new Buyer());
}
This should compile, since a Buyer is an object.
However, if you pass a BaseCollection<Seller>, you just tried to add a buyer to a list of sellers.
Thus, the statement
BaseCollection<Seller> is a subtype of BaseCollection<object>
only holds if BaseCollection ensures that the generic type T is only used in output positions. The Add example above would use T in an input position.
To solve this, you have the following options:
Make BaseCollection "covariant" by adding the out keyword, which would require removing any Add methods. This, however, might make your collection kind of useless.
Pass a covariant interface to the method. If you only need to read serverItems, pass an IEnumerable, which is already covariant (and you mention in the comments that BaseCollection already implements IEnumerable):
private List<ClientItem> ConvertToClientItems(IEnumerable<object> serverItems) {
// You can only read serverItems here, so we are fine.
}
make the method itself generic
private List<ClientItem> ConvertToClientItems<T>(BaseCollection<T> serverItems) {
// This also prevents the evil `Add` call, since you'd need to create
// an object of the correct type T first.
}
In BaseCollection, you have to make T covariant by using the "out" keyword.
More information http://msdn.microsoft.com/en-us/library/dd233059.aspx.
(IEnumerable works because it is covariant.)
public interface BaseCollection<out T>
So my real method is a lot different but I come down to this. It seems I don't fully understand how to handle the generic <T> type when I'm working with generic methods. My understanding is that we use generic methods when we want the same logic to work for different types, but we want the freedom to determine the exact type at run time. So it seems pretty natural to me that when I have a method like this :
internal static void ChangeCode<T>(Entity entity) where T : Entity
{
T tempEntity;
if (entity.GetType() == typeof(SomeMoreSpecificEntity))
{
tempEntity = new SomeMoreSpecificEntity();
}
}
However if I try something like this I get an error Can not convert type T to SomeMoreSpecificEntity.
So where am I wrong. Isn't the idea to be able to do exactly this - declare a common type in compile time and cast to more specific type in run time?
You can't do that. Check following situation:
You have another class named SomeMoreSpecificEntity2 which is declared:
class SomeMoreSpecificEntity2 : Entity
{
}
You call your method ChangeCode<SomeMoreSpecificEntity2>, so T is SomeMoreSpecificEntity2, so tempEntity is SomeMoreSpecificEntity2 as well, but you're trying to assign SomeMoreSpecificEntity to it. That can't work.
You can try changing it to :
internal static void ChangeCode<T>(Entity entity) where T : Entity
{
Entity tempEntity;
if (entity.GetType() == typeof(SomeMoreSpecificEntity))
{
tempEntity = new SomeMoreSpecificEntity();
}
}
It compiles.
No, the code you're trying to write is broken. For example, suppose I called:
ChangeCode<BananaEntity>(new SomeMoreSpecificEntity());
That would try to assign a reference of type SomeMoreSpecificEntity to a variable of type T, where T is BananaEntity.
It's not clear what you're trying to achieve, but that's why your current code won't compile. Given that you're not actually using T other than for a purpose for which it won't work your current code could be changed to make it a non-generic method, and just declare tempEntity as type Entity. Of course, that might not work for what you really want to do, but as you've only provided the non-working code, that's hard to determine :(
Three points about this line:
if (entity.GetType() == typeof(SomeMoreSpecificEntity))
Did you actually mean entity to be of type T rather than type Entity? Currently it can be any entity
Did you really want to check the exact type? Normally you'd use is instead of calling GetType and comparing it directly with a type
Normally comparing types like this is a sign that you should consider a redesign. It's definitely not generic at this point, as it only copes with types that are hard-coded in it.
tempEntity = (T)(object)new SomeMoreSpecificEntity();
T can only cast with object
I have a method
private object SetGrid(IGrid grid)
{
grid.PagerHelper.SetPage(1, 10);
grid.SortHelper.SetSort(SortOperator.Ascending);
grid.PagerHelper.RecordsPerPage = 10;
return grid;
}
which returns an object of type object.
Then I cast the object back to the previous type.
var projectModel = new ProjectModel();
projektyModel = (ProjectModel)SetGrid(projectModel);
The gain of this is, the method SetGrid can be reused across the app.
Is this a common practice or should I avoid doing this ?
You could use a generic method instead, and constrain the type argument to your IGrid interface:
private T SetGrid<T>(T grid) where T : IGrid
{
grid.PagerHelper.SetPage(1, 10);
grid.SortHelper.SetSort(SortOperator.Ascending);
grid.PagerHelper.RecordsPerPage = 10;
return grid;
}
You should still be able to call the method in exactly the same way, just without the cast. Type inferencing should be capable of automagically figuring out the required generic type argument for you:
var projectModel = new ProjectModel();
projektyModel = SetGrid(projectModel);
EDIT...
As other answers have mentioned, if your IGrid objects are reference types then you don't actually need to return anything at all from your method. If you pass a reference type then your method will update the original object, not a copy of it:
var projectModel = new ProjectModel(); // assume that ProjectModel is a ref type
projektyModel = SetGrid(projectModel);
bool sameObject = object.ReferenceEquals(projectModel, projektyModel); // true
Since you are passing in an object of a class that implements IGrid you could just as well change the return type to IGrid.
Also, since it's a reference type you don't even need to return the grid again. You could just as well use this:
var projectModel = new ProjectModel();
SetGrid(projectModel);
This is better accomplished with generics. You can use a constraint on the generic typeparam to preserve your type safety!
private T SetGrid<T>(T grid) where T : IGrid
{
grid.PagerHelper.SetPage(1, 10);
grid.SortHelper.SetSort(SortOperator.Ascending);
grid.PagerHelper.RecordsPerPage = 10;
return grid;
}
and then
var projectModel = new ProjectModel();
projectModel = SetGrid(projectModel);
Here, the generic typeparam "T" is actually inferred by the compiler by the way you call the method.
It's worth noting that in the particular use-case you've demonstrated, returning grid is probably unnecessary, as your original variable reference will be appropriately modified after the method call.
In the case you illustrate above there is no need to return grid. The IGrid instance is passed by reference, so your projectModel reference will be updated with the changes you've made in the SetGrid method.
If you still want to return the argument, at least return IGrid, since it is already known that the argument is an IGrid.
In general, provide as much type information as you can when programming in a statically typed language/manner.
"Is this a common practice or should I avoid doing this ?"
This is not common practice. You should avoid doing this.
Functions that only modify the parameter passed in should not have return types. If causes a bit of confusion. In the current C# you could make the modifying function an extention method for better read-ability.
It causes an unnecisary cast of the return type. It's a performance decrease, which may not be noticable... but its still needless since you are casting from an interface, return that interface even if the object is different from the parameter passed in.
Returning object is confusing to users of the function. Lets say the function created a copy and returned a copy... you would still want to return the interface passed in so that people using the function know "hey i'm getting an IGrid back." instead of having to figure out what type is being returned on thier own. The less you make your team mates think about stuff like this the better, for you and them.
This is a very weird example because SetGrid doesn't seem to do a lot of things other than setting some defaults. You are also letting the code perform manipulation on the object that could very well do that by itself. Meaning IGrid and ProjectModel could be refactored to this:
public interface IGrid {
// ...
public void setDefaults();
// ...
}
public class ProjectModel : IGrid {
// ...
public void setDefaults() {
PagerHelper.SetPage(1, 10);
SortHelper.SetSort(SortOperator.Ascending);
PagerHelper.RecordsPerPage = 10;
}
// ...
}
Using this refactoring you only need perform the same with this:
myProjectModel.setDefaults();
You could also create an abstract base class that implements IGrid that implements the setDefaults() method and let ProjectModel extend the abstract class.
what about the SOLID principles ? Concretely the Single Responsibility Principle. The class is in the first place something like a DTO. – user137348
I'm exercising the Interface Segregation Principle out of the SOLID principles here, to hide the implementation from the client of the class. I.e. so the client doesn't have to access the internals of the class it is using or else it is a violation of Principle of Least Knowledge.
Single Responsibility Principle (SRP) only tells that a class should only have one reason to change which is a very vague restriction since a change can be as narrow and broad as you want it to be.
I believe it is okay to put some configuration logic in a parameter class if it is small enough. Otherwise I'd put it all in a factory class. The reason I suggest this solution is because IGrid seems to have reference to PagerHelper and SortHelper that seem to be mutators for IGrid.
So I find it odd that you mention the class being a DTO. A DTO from a purist sense shouldn't have logic in it other than accessors (i.e. getter methods) which makes it strange that ProjectModel itself has references to PagerHelper and SortHelper which I assume can mutate it (i.e. they're setters). If you really want SRP the "helpers" should be in a factory class that creates the IGrid/ProjectModel instance.
Your grid is an IGrid, why not return IGrid?
I've written a resolver so I can have a very primitive DI framework. In the framework I allow for a dependency resolver to specify what default types to load if nothing is specified or registered.
However, the way I do the default loading has got me wondering. I'm not sure I'm doing it the best way it could be done.
Example:
T LoadDefaultForType<T>()
{
T _result = default(T);
if (typeof(T) == typeof(ISomeThing)
{
result = new SomeThing();
}
... more of the same
else
{
throw new NotSupportException("Give me something I can work with!");
}
return _result;
}
Update
The use of this would be to get the default object for a given interface in the event that a module or assembly has not configured the interface with a concrete type.
So for instance:
IoC.Resolve<ISomeThing>();
would need to return back to me a SomeThing object if nothing else has been registered to ISomeThing. The LoadDefaultForType in this case is kind of a last ditch effort to use a default (in this case whatever my domain model is).
The Resolve might shed some light on this as well:
T Resolve<T>()
{
T _result = default(T);
if (ContainedObjects.ContainsKey(typeof(T))
_result = (T)ContainedObjects[typeof(T)];
else
_result = LoadDefaultForType<T>();
return _result;
}
Any thoughts? Is there a better way to load default types given that I'm trying to allow for a Convention Over Configuration approach?
A few of suggestions:
You could create an attribute that can be used to mark the default implementation type of a particular interface. When you attempt to resolve the type, you could search for this attribute on T and use reflection to dynamically instantiate the type.
Alternatively, you could use reflection to search the available (loaded) assemblies or a concrete type that implements the interface. This can be a slow and expensive processes, so it would only make sense if the default case is rare.
Finally, if you're comfortable with naming conventions, you could search for a class that has the same name as the interface but without the leading "I". Not the best approach, but certainly one that can be made to work in a pinch.
public T LoadDefaultForType<T>()
where T : new()
{
T _result = new T();
return _result;
}
the code above would be a better way, but im not sure what it is your're trying todo, more information would help give u a better way of doing whatever it is you're trying to achieve.
I suggest taking a look at Unity for dynamically loading types, ie. Dependency injection
Neil's approach is the best if T can be resolved (I think it also has to be in the same assembly?).
Within your class, you could create an internal "registry" of sorts that could be used with System.Reflection to instantiate items without the giant switch statement. This preserves your "convention over configuration" while also keeping you DRY.
Edit
Combined with one aspect of LBushkin's answer to show some working code. (At least, it compiles in my head, and is taken from an example that I know works...)
public T LoadDefaultForType<T>()
{
try
{
string interfaceName = typeof(T).AssemblyQualifiedName;
// Assumes that class has same name as interface, without leading I, and
// is in ..."Classes" namespace instead of ..."Interfaces"
string className = interfaceName.Replace("Interfaces.I", "Classes.");
Type t = Type.GetType(className, true, true);
System.Reflection.ConstructorInfo info = t.GetConstructor(Type.EmptyTypes);
return (T)(info.Invoke(null));
}
catch
{
throw new NotSupportException("Give me something I can work with!");
}
}
Note that - as written - it won't work across assembly boundaries. It can be done using essentially the same code, however - you just need to supply the assembly-qualified name to the Type.GetType() method. (fixed - use AssemblyQualifiedName instead of FullName; assumes that interface and implementing class are in same assembly.)
One way would be to have a list of AssemblyQualifiedName pairs, with the first containing the base type and the second containing the child to be insantiated. It could be in your App.config or an XML file or whatever else is convenient. Read this list during start-up and use it to populate a Dictionary to use as a look-up table. For the key, you could use the AssemblyQualifiedName of the base, or perhaps the corresponding Type instance. For the value, you should probably consider getting the ConstructorInfo for the child type.
A better way to load the default types is to provide an add method that stores the type in a hash table. This decouples the dependency container from the registration logic.
You may choose later to change the registration code to read the types from some file or something.