i'm implementing a generic interface (iqueryprovider, specifically). at some point, i'm forced to return a generic result, that i need to get from some internal interface:
public TResult Execute<TResult>(...) {
return something.Foo<TResult>();
}
where something.Foo is
public T Foo<T>() where T: MyBaseClass, new() {
...
}
this of course blows up because the externally defined TResult doesn't have the same type restrictions as the internally-defined T. the question: is there a way to make TResult palatable to Foo? can i somehow explicitly test for those two conditions and coerce the type variable?
You could try something like this:
public TResult Execute<TResult>(...)
{
if (typeof(TResult) is MyBaseClass)
{
Type mytype = typeof(TResult);
MethodInfo method = typeof({TypewhereFoo<>IsDeclared}).GetMethod("Foo");
MethodInfo generic = method.MakeGenericMethod(myType);
return (TResult)generic.Invoke(this, null);
}
else
{
// Throw here
}
}
Nope. If TResult has no constraints on it, then it can be any old thing. If your helper method cannot take any old thing, then you'll need to get a better helper method. The interface requires you to provide more services than your helper can provide, therefore, you're going to have to do the work to provide that service.
You will have to add the type restrictions to your generic method:
public TResult Execute<TResult>(...) where TResult: MyBaseClass, new() {
return something.Foo<TResult>();
}
Ouch... you have a problem. There is no way to call something.Foo() since you do not have a type that is compatible. You could 'hack' around this by creating a 'wrapper' type that is compatible to call the Foo() and then 'unwrap' :
class MyNastyFix<T> : MyBaseClass
{
public T Unwrap()
{
//assert that T has the correct base type
if (!typeof(T).IsSubclassOf(typeof(MyBaseClass)))
throw new ArgumentException();
//must use reflection to construct
T obj = (T)typeof(T).InvokeMember(null, BindingFlags.CreateInstance, null, null, null);
//cast to a type of MyBaseClass so we can copy our values
MyBaseClass c = (MyBaseClass)(object)obj;
c.SomeValue = this.SomeValue;
return obj;
}
}
public static TResult Execute<TResult>()
{
return something.Foo<MyNastyFix<TResult>>().Unwrap();
}
Update: The reflection answer might be a better approach if that works.
Change Foo to check the constraints at run-time:
public T Foo<T>() {
if (!typeof(T).IsAssignableFrom(typeof(MyBaseClass))
|| !typeof(T).GetConstructor(...))
throw new System.NotImplementedException();
...
}
The generic constraints are checked at compile-time so they can't be based on run-time conditions.
Related
I'm working on a Fluent Api for a service which is fairly configurable, and just trying to work my options for a neat solution for the following problem.
I have a class something like this
public class WindowVm : DialogResultBase<MyReturnType>
All well and good, However can any one think of a way to achieve the following without having to verbosely specify the second generic type given i.e
public IDialogWithResult<TViewModel, TSomeReturnType> DialogWithResult<TViewModel,TSomeReturnType>(object owner = null)
where TViewModel : DialogResultBase<TSomeReturnType>
i really am just interest in the result IDialogWithResult<TViewModel, TSomeReturnType> even if i have to do this in 2 statements
So i can call
.DialogWithResult<WindowVm>()
I know all the information is there and declared at compile time, also i know this is Partial Inference and its all or nothing. However i just wondering if there is some trick without having to redeclare
.DialogWithResult<WindowVm, ResultType>();
Moreover i have a method that needs ResultType as (you guessed it) a result type
ResultType MyResult = ...DialogWithResult<WindowVm, ResultType>()
.ShowModal();
I mean, ResultType is really just superfluous at this point in the
game as its already been declared by WindowVm. it would be nice if
the consumer didn't have to go looking for it (even if it meant more
than one step)
Yes, compiler has all the information to infer the type for TSomeReturnType when you pass WindowVm as TViewModel. But the main obstacle for allowing reduced argument list for generic (.DialogWithResult<WindowVm>()) is that it could conflict with overloaded method with the same name but just one generic type argument. For example if you have following methods in the class:
public IDialogWithResult<TViewModel, TSomeReturnType> DialogWithResult<TViewModel,TSomeReturnType>(object owner = null)
where TViewModel : DialogResultBase<TSomeReturnType>
public IDialogWithResult<TViewModel> DialogWithResult<TViewModel>(object owner = null)
where TViewModel : DialogResultBase<MyReturnType>
Which one should compiler call when you code .DialogWithResult<WindowVm>() ?
That's the reason why such simplified syntax will probably not be introduced in C#.
However you still have an option to make the calls as simple as .DialogWithResult<WindowVm>(). I'm not a fan of this solution but if brevity of your Fluent Api calls is important, you could use it. The solution is based on reflection and run-time extraction of TSomeReturnType type from passed TViewModel type:
public class YourClass
{
public dynamic DialogWithResult<TViewModel>(object owner = null)
{
// Searching for DialogResultBase<TSomeReturnType> in bases classes of TViewModel
Type currType = typeof(TViewModel);
while (currType != null && currType != typeof(DialogResultBase<>))
{
if (currType.IsGenericType && currType.GetGenericTypeDefinition() == typeof(DialogResultBase<>))
{
break;
}
currType = currType.BaseType;
}
if (currType == null)
{
throw new InvalidOperationException($"{typeof(TViewModel)} does not derive from {typeof(DialogResultBase<>)}");
}
Type returnValueType = currType.GetGenericArguments()[0];
// Now we know TViewModel and TSomeReturnType and can call DialogWithResult<TViewModel, TSomeReturnType>() via reflection.
MethodInfo genericMethod = GetType().GetMethod(nameof(DialogWithResultGeneric));
if (genericMethod == null)
{
throw new InvalidOperationException($"Failed to find {nameof(DialogWithResultGeneric)} method");
}
MethodInfo methodForCall = genericMethod.MakeGenericMethod(typeof(TViewModel), returnValueType);
return methodForCall.Invoke(this, new [] { owner } );
}
public IDialogWithResult<TViewModel, TSomeReturnType> DialogWithResultGeneric<TViewModel, TSomeReturnType>(object owner = null)
where TViewModel : DialogResultBase<TSomeReturnType>
{
// ...
}
}
We declared new DialogWithResult<TViewModel>() method with just one generic type argument of TViewModel. Then we search for the base DialogResultBase<T> class. If found we extract type of TSomeReturnType with Type.GetGenericArguments() call. And finally call original DialogWithResultGeneric<TViewModel, TSomeReturnType> method via reflection. Note that I have renamed original method to DialogWithResultGeneric so that GetMethod() does not throw AmbiguousMatchException.
Now in your program you could call it as:
.DialogWithResult<WindowVm>()
The downside is that nothing prevents you from calling it on wrong type (the one does not inherit from DialogResultBase<T>):
.DialogWithResult<object>()
You won't get compilation error in this case. The problem will be identified only during run-time when exception will be thrown. You could fix this issue with a technique described in this answer. In short, you should declare non-generic DialogResultBase and set it as the base for DialogResultBase<T>:
public abstract class DialogResultBase
{
}
public class DialogResultBase<T> : DialogResultBase
{
// ...
}
Now you could add constraint on DialogWithResult<TViewModel>() type parameter:
public dynamic DialogWithResult<TViewModel>(object owner = null)
where TViewModel : DialogResultBase
Now .DialogWithResult<object>() will cause compilation error.
Again, I'm not a big fan of solution that I proposed. However you can't achieve what you're asking for with just C# capabilities.
As both you and #CodeFuller observed, partial inference isn't possible in C#.
If you're looking for something less evil than going dynamic, you can use a combination of extension methods and custom classes to get the types you need without ever referring directly to the return type.
In the example below, I use an extension method on DialogResultBase<T> to infer the return type and then I return a helper class containing a generic method for DialogWithResult<WindowVm>.
Still not pretty, but roughly fits what you asked for.
Interesting point about inference. Each parameter can only be used to infer a single type. If you were to pass the same parameter multiple times, you can infer multiple types from it. i.e. if you pass the same parameter to both parameters in (T myList, List<TItem> myListAgain) you could infer both the list type and the item type.
public class Class2
{
public static void DoStuff()
{
var dialogResult = default(WindowVm).GetReturnType().DialogWithResult<WindowVm>();
}
}
public class MyReturnType { }
public class DialogResultBase<T> : IDialogWithResult<T> { }
public interface IDialogWithResult<TSomeReturnType> { }
public class WindowVm : DialogResultBase<MyReturnType> { }
public class DialogResultHelper<TSomeReturnType>
{
public IDialogWithResult<TSomeReturnType> DialogWithResult<TViewModel>() where TViewModel : DialogResultBase<TSomeReturnType>, new()
{
return new TViewModel();
}
}
public static class Extensions
{
public static DialogResultHelper<T> GetReturnType<T>(this DialogResultBase<T> dialogResultBase)
{
return new DialogResultHelper<T>();
}
}
In C#, I have a function that passes in T using generics and I want to run a check to see if T is an object that implements a interface and if so call one of the methods on that interface.
I don't want to have T constraints to only be of that Type. Is it possible to do this?
For example:
public class MyModel<T> : IModel<T> where T : MyObjectBase
{
public IQueryable<T> GetRecords()
{
var entities = Repository.Query<T>();
if (typeof(IFilterable).IsAssignableFrom(typeof(T)))
{
//Filterme is a method that takes in IEnumerable<IFilterable>
entities = FilterMe(entities));
}
return entities;
}
public IEnumerable<TResult> FilterMe<TResult>(IEnumerable<TResult> linked) where TResult : IFilterable
{
var dict = GetDict();
return linked.Where(r => dict.ContainsKey(r.Id));
}
}
The error that I am getting is:
Error 21 The type 'TResult' cannot be used as type parameter 'TResult' in the generic type or method 'FilterMe(System.Collections.Generic.IEnumerable)'. There is no implicit reference conversion from 'TResult' to 'IFilterable'.
The missing piece is Cast<>():
if(typeof(IFilterable).IsAssignableFrom(typeof(T))) {
entities = FilterMe(entities.Cast<IFilterable>()).AsQueryable().Cast<T>();
}
Note the use of Cast<>() to convert the entities list to the correct subtype. This cast would fail unless T implements IFilterable, but since we already checked that, we know that it will.
if (typeof(IMyInterface).IsAssignableFrom(typeof(T))
This checks whether a variable of type IMyInterface can be assigned from an instance of type T.
If you have a generic-type parameter that may or may not implement IFoo, it's possible to as cast it to a storage location of type IFoo; if you do that, you may pass it to any method which expects an IFoo, as well as any method that expects a generic parameter constrained to IFoo, but you will lose all generic type information if you do that--the parameter will be passed as type IFoo. Among other things, this will mean that if your original object was a structure, it will be boxed.
If you wish to test whether a generic parameter type implements IFoo and call a method that takes a generic-constrained IFoo if it does, while keeping the original generic type (this could be useful if the type is a struct, and could be necessary if the type is being passed to a generic method which has both IFoo and IBar constraints and the things one might want to pass do not share any single common supertype), it will be necessary to use Reflection.
For example, suppose one wants to have a method Zap which takes a generic ref parameter, calls Dispose on it if it implements IDisposable, and clears it out. If the parameter is an IDisposable class type, a null test should be performed as an atomic operation with clearing out the parameter.
public static class MaybeDisposer
{
static class ClassDisposer<T> where T : class,IDisposable
{
public static void Zap(ref T it)
{
T old_it = System.Threading.Interlocked.Exchange(ref it, null);
if (old_it != null)
{
Console.WriteLine("Disposing class {0}", typeof(T));
old_it.Dispose();
}
else
Console.WriteLine("Class ref {0} already null", typeof(T));
}
}
static class StructDisposer<T> where T : struct,IDisposable
{
public static void Zap(ref T it)
{
Console.WriteLine("Disposing struct {0}", typeof(T));
it.Dispose();
it = default(T);
}
}
static class nonDisposer<T>
{
public static void Zap(ref T it)
{
Console.WriteLine("Type {0} is not disposable", typeof(T));
it = default(T);
}
}
class findDisposer<T>
{
public static ActByRef<T> Zap = InitZap;
public static void InitZap(ref T it)
{
Type[] types = {typeof(T)};
Type t;
if (!(typeof(IDisposable).IsAssignableFrom(typeof(T))))
t = typeof(MaybeDisposer.nonDisposer<>).MakeGenericType(types);
else if (typeof(T).IsValueType)
t = typeof(MaybeDisposer.StructDisposer<>).MakeGenericType(types);
else
t = typeof(MaybeDisposer.ClassDisposer<>).MakeGenericType(types);
Console.WriteLine("Assigning disposer {0}", t);
Zap = (ActByRef<T>)Delegate.CreateDelegate(typeof(ActByRef<T>), t, "Zap");
Zap(ref it);
}
}
public static void Zap<T>(ref T it)
{
findDisposer<T>.Zap(ref it);
}
}
The first time the code is invoked with any type T, it will determine what sort of generic static class can be produced for that parameter and use Reflection to create a delegate to call a static method of that generic class. Subsequent calls with the same type T will use the cached delegate. Even though Reflection can be a little slow, it will only need to be used once for any type T. All subsequent calls to MaybeDisposer.Zap<T>(ref T it) with the same type T will be dispatched directly through the delegate and will thus execute quickly.
Note that the calls to MakeGenericType will throw exceptions if they are given generic type parameters which do not meet the constraints of the given open generic classes (e.g. if T was a class or did not implement IDisposable, an attempt to make the generic type StructDisposer<T> would throw an exception); such tests occur at run-time and are not validated by the compiler, so you can use run-time checking to see if the types meet appropriate constraints. Note that the code does not test whether it implements IDisposable, but instead tests whether T does. This is very important. Otherwise, if MaybeDispose was called with a parameter of type Object which held a reference to a Stream, it would determine that it implemented IDisposable and thus try to create a ClassDisposer<Object>, crashing because Object does not implement IDisposable.
The simplest form I can come up with is something like:
public IEnumerable<T> GetRecords()
{
IQueryable<T> entities = new List<T>().AsQueryable();
if (typeof(IFilterable).IsAssignableFrom(typeof(T)))
{
entities = FilterMe<IFilterable, T>(entities.OfType<IFilterable>()).AsQueryable();
}
return entities;
}
public IEnumerable<TResult> FilterMe<TSource, TResult>(IEnumerable<TSource> linked) where TSource : IFilterable
{
return linked.Where(r => true).OfType<TResult>();
}
The point here is the need to have types to pass into and get back out of the method. I had to change the types locally to get it working.
OfType will silently filter out items that are not really of a given type, so it assumes that it's a collection of the same type in any one call.
Because you are re-assigning from FilterMe, you still need the interface assignable check.
Is the OfType(...) method (link) what you're looking for?
public class MyModel<T> : IModel<T> where T : MyObjectBase
{
public IQueryable<T> GetRecords()
{
var entities = Repository.Query<T>();
if (typeof(IFilterable).IsAssignableFrom(typeof(T)))
{
//Filterme is a method that takes in IEnumerable<IFilterable>
entities = FilterMe(entities));
}
return entities;
}
public IEnumerable<TResult> FilterMe<TResult>(IEnumerable<TResult> linked) where TResult : IFilterable
{
var dict = GetDict();
return linked.OfType<TResult>().Where(r => dict.ContainsKey(r.Id));
}
}
In my answer, I assume that method FilterMe is used internally and should not be visible outside your model and could be marked private. If my assumption is wrong, you could create a private overload of FilterMe.
In my answer I just removed the generic <TResult>. I assume that this FilterMe always is about then entities of type T (since it is in the same Model class). This solves the problem about casting between T and TResult. TResult does not have to be marked as IFilterable since none of the members of IFilterable are used. And since the code already checks if T is IFilterable why check again (especially when FilterMe would be private)?
public IQueryable<T> GetRecords()
{
var entities = Repository.Query<T>();
if (typeof(IFilterable).IsAssignableFrom(typeof(T)))
{
//Filterme is a method that takes in IEnumerable<IFilterable>
entities = FilterMe(entities).AsQueryable();
}
return entities;
}
public IEnumerable<T> FilterMe(IEnumerable<T> linked)
{
var dict = GetDict();
return linked.Where(r => dict.ContainsKey(r.Id));
}
If you would create a second FilterMe, replace the IEumerable<T> types with Queryable<T>, so you do not have to convert your entities with AsQueryable().
public IEnumerable<TResult> FilterMe<TResult>(IEnumerable<TResult> linked) where TResult : IFilterable
{
var dict = GetDict();
return linked.Where(r => dict.ContainsKey(r.Id));
}
Try replacing FilterMe with this version:
public IEnumerable<T> FilterMe(IEnumerable<IFilterable> linked)
{
var dict = GetDict();
return linked.Where(r => dict.ContainsKey(r.Id)).Cast<T>();
}
Then, were you call, change your code to this:
if (typeof(IFilterable).IsAssignableFrom(typeof(T)))
{
//Filterme is a method that takes in IEnumerable<IFilterable>
var filterable = entities.Cast<IFilterable>();
entities = FilterMe(entities).AsQueryable();
}
You don't have to make the FilterMe method a generic method to achieve the same result.
public class MyModel<T> : IModel<T> where T : MyObjectBase {
public IQueryable<T> GetRecords()
{
var entities = Repository.Query<T>();
if (typeof(IFilterable).IsAssignableFrom(typeof(T)))
{
//Filterme is a method that takes in IEnumerable<IFilterable>
entities = FilterMe(entities.Cast<IFilterable>());
}
return entities;
}
public IEnumerable<T> FilterMe(IEnumerable<IFilterable> linked) {
var dict = GetDict();
return linked
.Where(r => dict.ContainsKey(r.Id))
.Cast<T>();
}
}
why do I get a compiler error in the following code stating: Cannot implicty convert type SpecialNode to T even though T must derive from NodeBase as I defined in the where clause and even though SpecialNode actually derived from NodeBase?
public static T GetNode<T>() where T : NodeBase
{
if (typeof(T) == typeof(SpecialNode))
{
return ThisStaticClass.MySpecialNode; // <-- compiler error
}
if (typeof(T) == typeof(OtherSpecialNode))
{
return ThisStaticClass.MyOtherSpecialNode; // <-- compiler error
}
...
return default(T);
}
The compiler doesn't read your if check to realize that in this particular line, T must be SpecialNode.
You need to cast to NodeBase first, like this:
return (T)(NodeBase)MySpecialNode;
You need to casts because (as far as the compiler knows) T might be MyOtherSpecialNode, and you cannot cast a MyOtherSpecialNode to MySpecialNode.
EDIT: You can do it with a single cast like this:
NodeBase retVal;
if (typeof(T) == typeof(SpecialNode))
retVal = MySpecialNode;
else if (typeof(T) == typeof(OtherSpecialNode))
retVal = MyOtherSpecialNode;
return (T)retVal;
You might see that a condition has been logically met, but the compiler does not "remember" this.
public static T GetNode<T>() where T : NodeBase
{
if (typeof(T) == typeof(SpecialNode)) // OK, you now know T is SpecialNode
{
// the compiler still insists on returning a T,
// and will not assume that MySpecialNode is a T
return MySpecialNode;
}
// ...
return default(T);
}
It's true what others have already said: you must cast MySpecialNode: (T)(NodeBase)MySpecialNode (which you can do safely, because you have already checked that T is SpecialNode).
It's easy to think of this as a shortcoming of the compiler; but this is just a mistake stemming from how obvious it seems that MySpecialNode is a T. Suppose I had a method like this:
public T Get<T>() {
if (typeof(T).FullName.Equals("System.Int32"))
return 5;
else
return default(T);
}
Should this compile? I should hope not; the compiler needs to guarantee that it's returning an object of type T, and it can't be sure that 5 will meet that requirement just from some bizarre check that I the developer have performed. (Yes, I know that T is int, but I would not expect any reasonable compiler to determine that from a comparison of the System.Type.FullName property.)
Checking if (typeof(T) == typeof(SpecialNode)) is really not so different from that.
The problem is that the function may be called with a type parameter T, which derives from NodeBase but not from SpecialNode. The compiler doesn't check the semantics of the if statement, so it doesn't know, that T has to be a specialNode.
You would need to use an explicit cast to T in order to satisfy your compiler.
You could also do:
public static T GetNode<T>() where T : NodeBase
{
T result;
result = ThisStaticClass.MySpecialNode as T;
if (result != null) return result;
result = ThisStaticClass.MyOtherSpecialNode as T;
if (result != null) return result;
return default(T);
}
Edit: If the static classes are already null, this probably wouldn't have the intended effect.
Ah, that moment you wish the language had some kinda static polymorphism. Type checking in a generic method is not very cool. This can be a better solution if your requirements let:
public abstract class NodeBase
{
public abstract NodeBase GetNode();
}
public class SpecialNode : NodeBase
{
public override NodeBase GetNode()
{
return ThisStaticClass.MySpecialNode;
}
}
public class OtherSpecialNode : NodeBase
{
public override NodeBase GetNode()
{
return ThisStaticClass.MyOtherSpecialNode;
}
}
//and in your generic method, just:
public static T GetNode<T>() where T : NodeBase, new()
{
return (T)new T().GetNode();
}
This suffer from a disadvantage that you have to expose a parameterless constructor. In case that's undesirable, may be a slightly better approach is to push the generic call one layer backward, and ask your static class itself to do the work for you. Changing static class definition to something like:
public static T GetNode<T>() where T : NodeBase
{
return ThisStaticClass<T>.GetNode();
}
//in which case ThisStaticClass<T> have awareness of
//parameterless new() constructor of T class, which still need not be good enough
You can get it a bit more strongly typed by going one generic level deeper.
public abstract class NodeBase<T> where T : NodeBase<T>
{
public abstract T GetNode();
}
public class SpecialNode : NodeBase<SpecialNode>
{
public override SpecialNode GetNode()
{
return ThisStaticClass.MySpecialNode;
}
}
public class OtherSpecialNode : NodeBase<OtherSpecialNode>
{
public override OtherSpecialNode GetNode()
{
return ThisStaticClass.MyOtherSpecialNode;
}
}
//avoids cast
public static T GetNode<T>() where T : NodeBase<T>, new()
{
return new T().GetNode();
}
Why not just do the following:
return (T)MySpecialNode;
What version of .NET?
See my answer from a previous post
Using Generics to return a literal string or from Dictionary<string, object>
but the answer is
return (T)MySpecialNode
Because even you do the if check the compiler does not so you have to recast to T
I'm wondering if it's possible to cast an object to a Type... I've just started using Reflection, so maybe I'm doing it all wrong but here's what I would like to do:
...
Type type = ...;
Type interfaceType = someOtherType.GetInterface("IConverter`2");
return (Cast to interfaceType)Activator.CreateInstance(type);
Is the cast to the interface possible?
Update:
Compiler says that T and K can not be found. The myInterface Type instance knows the T and K class...
public IConverter<T, K> GetConverter(Type type)
{
if (dtoModelDictionary.ContainsKey(type))
{
Type foundType = dtoModelDictionary[type];
Type myInterface = foundType.GetInterface("IConverter`2");
return (IConverter<T, K>)Activator.CreateInstance(foundType);
}
else if (dalModelDictionary.ContainsKey(type))
{
Type foundType = dalModelDictionary[type];
return (IConverter<T, K>)Activator.CreateInstance(foundType);
}
else
{
throw new System.Exception();
}
}
Second update:
public SomeClass GetConverter(Type type)
{
if (dtoModelDictionary.ContainsKey(type))
{
Type foundType = dtoModelDictionary[type];
Type myInterface = foundType.GetInterface("IConverter`2");
IConverter<T, K> converter = (IConverter<T, K>)Activator.CreateInstance(foundType);
return converter.someMethod();
}
}
Answer to you update:
You cannot cast to a type where the generic arguments are not defined. T and K must be defined for the method that is using it.
Either declare it:
public IConverter<T, K> GetConverter<T, K>(Type type)
Or, if you face the problem often that this interface is used but you don't know any T or K types, use an interface without generics:
interface IConverter
{
// general members
}
interface IConverter<T, K> : IConverter
{
// typesave members
}
public IConverter GetConverter(Type type)
{
// ...
return (IConverter)Activator.CreateInstance(type);
}
Not really, no... at least not in this way. The problem is that your return value is going to have to be whatever your method's return value is typed as. Because everything must be typed at compile-time, there is limited or no real use case that I can see for this particular kind of type coersion - maybe you can say some more about what you are trying to accomplish?
Now if you are using generics, you do have a run-time typing story, you can return your Type parameter type:
public T MyMethod<T>(...)
...
return (T)Activator.CreateInstance(type);
You can only cast an object to something that it actually is. You can for example cast a String reference to IEnumerable, but you can't cast it to char[].
If what your method returns actually implements the interface, you can just cast it as usual.
Example:
return (IConverter<int,string>)Activator.CreateInstance(type);
Edit:
You need to make the method generic so that you can specify the data types when you call it:
public IConverter<T, K> GetConverter<T, K>(Type type) {
...
}
You can do this:
var type = typeof(IConverter<,>).MakeGenericType(new Type[] { typeof(T), typeof(K) });
My question concerns c# and how to access Static members ... Well I don't really know how to explain it (which kind of is bad for a question isn't it?) I will just give you some sample code:
Class test<T>{
int method1(Obj Parameter1){
//in here I want to do something which I would explain as
T.TryParse(Parameter1);
//my problem is that it does not work ... I get an error.
//just to explain: if I declare test<int> (with type Integer)
//I want my sample code to call int.TryParse(). If it were String
//it should have been String.TryParse()
}
}
So thank you guys for your answers (By the way the question is: how would I solve this problem without getting an error). This probably quite an easy question for you!
Edit: Thank you all for your answers!
Though I think the try - catch phrase is the most elegant, I know from my experience with vb that it can really be a bummer. I used it once and it took about 30 minutes to run a program, which later on only took 2 minutes to compute just because I avoided try - catch.
This is why I chose the switch statement as the best answer. It makes the code more complicated but on the other hand I imagine it to be relatively fast and relatively easy to read. (Though I still think there should be a more elegant way ... maybe in the next language I learn)
Though if you have some other suggestion I am still waiting (and willing to participate)
The problem is that TryParse isn't defined on an interface or base class anywhere, so you can't make an assumption that the type passed into your class will have that function. Unless you can contrain T in some way, you'll run into this a lot.
Constraints on Type Parameters
Short answer, you can't.
Long answer, you can cheat:
public class Example
{
internal static class Support
{
private delegate bool GenericParser<T>(string s, out T o);
private static Dictionary<Type, object> parsers =
MakeStandardParsers();
private static Dictionary<Type, object> MakeStandardParsers()
{
Dictionary<Type, object> d = new Dictionary<Type, object>();
// You need to add an entry for every type you want to cope with.
d[typeof(int)] = new GenericParser<int>(int.TryParse);
d[typeof(long)] = new GenericParser<long>(long.TryParse);
d[typeof(float)] = new GenericParser<float>(float.TryParse);
return d;
}
public static bool TryParse<T>(string s, out T result)
{
return ((GenericParser<T>)parsers[typeof(T)])(s, out result);
}
}
public class Test<T>
{
public static T method1(string s)
{
T value;
bool success = Support.TryParse(s, out value);
return value;
}
}
public static void Main()
{
Console.WriteLine(Test<int>.method1("23"));
Console.WriteLine(Test<float>.method1("23.4"));
Console.WriteLine(Test<long>.method1("99999999999999"));
Console.ReadLine();
}
}
I made a static dictionary holding a delegate for the TryParse method of every type I might want to use. I then wrote a generic method to look up the dictionary and pass on the call to the appropriate delegate. Since every delegate has a different type, I just store them as object references and cast them back to the appropriate generic type when I retrieve them. Note that for the sake of a simple example I have omitted error checking, such as to check whether we have an entry in the dictionary for the given type.
To access a member of a specific class or interface you need to use the Where keyword and specify the interface or base class that has the method.
In the above instance TryParse does not come from an interface or base class, so what you are trying to do above is not possible. Best just use Convert.ChangeType and a try/catch statement.
class test<T>
{
T Method(object P)
{
try {
return (T)Convert.ChangeType(P, typeof(T));
} catch(Exception e) {
return null;
}
}
}
One more way to do it, this time some reflection in the mix:
static class Parser
{
public static bool TryParse<TType>( string str, out TType x )
{
// Get the type on that TryParse shall be called
Type objType = typeof( TType );
// Enumerate the methods of TType
foreach( MethodInfo mi in objType.GetMethods() )
{
if( mi.Name == "TryParse" )
{
// We found a TryParse method, check for the 2-parameter-signature
ParameterInfo[] pi = mi.GetParameters();
if( pi.Length == 2 ) // Find TryParse( String, TType )
{
// Build a parameter list for the call
object[] paramList = new object[2] { str, default( TType ) };
// Invoke the static method
object ret = objType.InvokeMember( "TryParse", BindingFlags.InvokeMethod, null, null, paramList );
// Get the output value from the parameter list
x = (TType)paramList[1];
return (bool)ret;
}
}
}
// Maybe we should throw an exception here, because we were unable to find the TryParse
// method; this is not just a unable-to-parse error.
x = default( TType );
return false;
}
}
The next step would be trying to implement
public static TRet CallStaticMethod<TRet>( object obj, string methodName, params object[] args );
With full parameter type matching etc.
This isn't really a solution, but in certain scenarios it could be a good alternative: We can pass an additional delegate to the generic method.
To clarify what I mean, let's use an example. Let's say we have some generic factory method, that should create an instance of T, and we want it to then call another method, for notification or additional initialization.
Consider the following simple class:
public class Example
{
// ...
public static void PostInitCallback(Example example)
{
// Do something with the object...
}
}
And the following static method:
public static T CreateAndInit<T>() where T : new()
{
var t = new T();
// Some initialization code...
return t;
}
So right now we would have to do:
var example = CreateAndInit<Example>();
Example.PostInitCallback(example);
However, we could change our method to take an additional delegate:
public delegate void PostInitCallback<T>(T t);
public static T CreateAndInit<T>(PostInitCallback<T> callback) where T : new()
{
var t = new T();
// Some initialization code...
callback(t);
return t;
}
And now we can change the call to:
var example = CreateAndInit<Example>(Example.PostInitCallback);
Obviously this is only useful in very specific scenarios. But this is the cleanest solution in the sense that we get compile time safety, there is no "hacking" involved, and the code is dead simple.
Do you mean to do something like this:
Class test<T>
{
T method1(object Parameter1){
if( Parameter1 is T )
{
T value = (T) Parameter1;
//do something with value
return value;
}
else
{
//Parameter1 is not a T
return default(T); //or throw exception
}
}
}
Unfortunately you can't check for the TryParse pattern as it is static - which unfortunately means that it isn't particularly well suited to generics.
The only way to do exactly what you're looking for would be to use reflection to check if the method exists for T.
Another option is to ensure that the object you send in is a convertible object by restraining the type to IConvertible (all primitive types implement IConvertible). This would allow you to convert your parameter to the given type very flexibly.
Class test<T>
{
int method1(IConvertible Parameter1){
IFormatProvider provider = System.Globalization.CultureInfo.CurrentCulture.GetFormat(typeof(T));
T temp = Parameter1.ToType(typeof(T), provider);
}
}
You could also do a variation on this by using an 'object' type instead like you had originally.
Class test<T>
{
int method1(object Parameter1){
if(Parameter1 is IConvertible) {
IFormatProvider provider = System.Globalization.CultureInfo.CurrentCulture.GetFormat(typeof(T));
T temp = Parameter1.ToType(typeof(T), provider);
} else {
// Do something else
}
}
}
Ok guys: Thanks for all the fish. Now with your answers and my research (especially the article on limiting generic types to primitives) I will present you my solution.
Class a<T>{
private void checkWetherTypeIsOK()
{
if (T is int || T is float //|| ... any other types you want to be allowed){
return true;
}
else {
throw new exception();
}
}
public static a(){
ccheckWetherTypeIsOK();
}
}
You probably cant do it.
First of all if it should be possible you would need a tighter bound on T so the typechecker could be sure that all possible substitutions for T actually had a static method called TryParse.
You may want to read my previous post on limiting generic types to primitives. This may give you some pointers in limiting the type that can be passed to the generic (since TypeParse is obviously only available to a set number of primitives ( string.TryParse obviously being the exception, which doesn't make sense).
Once you have more of a handle on the type, you can then work on trying to parse it. You may need a bit of an ugly switch in there (to call the correct TryParse ) but I think you can achieve the desired functionality.
If you need me to explain any of the above further, then please ask :)
Best code: restrict T to ValueType this way:
class test1<T> where T: struct
A "struct" here means a value type.
String is a class, not a value type.
int, float, Enums are all value types.
btw the compiler does not accept to call static methods or access static members on 'type parameters' like in the following example which will not compile :(
class MyStatic { public static int MyValue=0; }
class Test<T> where T: MyStatic
{
public void TheTest() { T.MyValue++; }
}
=> Error 1 'T' is a 'type parameter', which is not valid in the given context
SL.
That is not how statics work. You have to think of statics as sort of in a Global class even if they are are spread across a whole bunch of types. My recommendation is to make it a property inside the T instance that can access the necessary static method.
Also T is an actual instance of something, and just like any other instance you are not able to access the statics for that type, through the instantiated value. Here is an example of what to do:
class a {
static StaticMethod1 ()
virtual Method1 ()
}
class b : a {
override Method1 () return StaticMethod1()
}
class c : a {
override Method1 () return "XYZ"
}
class generic<T>
where T : a {
void DoSomething () T.Method1()
}