C# casting to object in interface generic - c#

i have a problem that I do not understand about casting in interfaces with generic (probably because covariance and contravariance are not completly clear to me at the moment).
I have an Interface where i define a getter and setter that should accept anything in a typed way (no object as type)
Eg :
public interface IDummy <T>
{
int SomeCommonMethod() ;
T Anything { get; set; }
}
Now i define some concretes implementation of interface defined before.
public class MyStrObj : IDummy <string>
{
private string _stirngVal = string.Empty ;
public int SomeCommonMethod()
{
return 0 ;
}
public string Anything
{
get { return _stirngVal ; }
set { _stirngVal = value ; }
}
}
public class MyFileObj : IDummy <File>
{
private File _file = null ;
public int SomeCommonMethod()
{
return 0 ;
}
public File Anything
{
get { return _file ; }
set { _file = value ; }
}
}
At time all works as expected, but now when try to use this two object their behaviour start becoming confusing for me.
I try to define an object that should be able to consume both previous classes (no matter which type they has in their generics, what matter is that they are IDummy).
public class Consumer
{
public static void Consume ( IDummy<object> obj )
{
//SOME CODE HERE.
}
}
Now if i try this code :
MyStrObj obj = new MyStrObj () ;
Consumer.Consume ( obj ) ;
then compiler notice to me that there are some invalid parameters over Consume method calling (obj sure), but there is not an implicit cast here?
If i try this way instead :
MyStrObj obj = new MyStrObj () ;
Consumer.Consume ( (IDummy<object>)obj ) ;
compiler seems to work as I suppose it should (at time I have not tested if the two calls are equivalent).
Thanks in advance for anyone that can help me to understand this behaviour, and sorry for my english (is not my language).

Your IDummy<T> is not covariant. That is why the implicit conversion of such does not work. If it were covariant, the conversion from more specific generic type to the more general one would work. However in your example you cannot make your interface covariant IDummy<out T>, since it has a property setter with your generic parameter.

The method in your Consumer class needs to be generic.
public class Consumer
{
public static void Consume<T> ( IDummy<T> obj )
{
//SOME CODE HERE.
}
}
Then you can do
var foo = new MyStrObj();
foo.Anything = "Hello";
Consumer.Consume(foo);

In order to achieve what you described using covariance you need to amend your interface to make it covariant.
Covariance allows you to assign more specific types to less specific. This is possible however only for the classes that only return your objects of the template type.
Hence in your interface you need to remove the setter ant mark the T as covariant using the keyword out. You can keep the setter on the classes that implement it though. So your interface would have to look like this:
public interface IDummy<out T>
{
int SomeCommonMethod();
T Anything { get; }
}
Your MyStrObj, MyFileObj and Consumer classes can stay as they are. After the change you can utilize the covariance when calling the Consume method.
MyStrObj obj = new MyStrObj();
obj.Anything = "My string";
Consumer.Consume(obj);

Related

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."

Creating a class or interface for a complex generic type

I am trying to create an alias for a type of list of list of object. Specifically, I want to shorten all the typing I have to do for this type:
IReadOnlyList<IReadOnlyList<MyObject>>
My attempt is demonstrated here:
using System.Collections.Generic;
namespace MyApp
{
class Program
{
public class MyObject
{
public static IMyCollection GetCollection()
{
var a = new List<MyObject>();
a.Add(new MyObject());
var b = new List<IReadOnlyList<MyObject>>();
b.Add(a.AsReadOnly());
return b.AsReadOnly();
}
}
public interface IMyCollection : IReadOnlyList<IReadOnlyList<MyObject>>
{
}
static void Main(string[] args)
{
var collection = MyObject.GetCollection();
}
}
}
Unfortunately, this won't compile. There error is:
Cannot implicitly convert type
'System.Collections.ObjectModel.ReadOnlyCollection<System.Collections.Generic.IReadOnlyList<MyApp.Program.MyObject>>'
to 'MyApp.Program.IMyCollection'.
An explicit conversion exists (are you missing a cast?)
OK, so I'm close. Perhaps explicitly casting? So I change the return statement in GetCollection to
return (IMyCollection)b.AsReadOnly();
That compiles, albeit with a resharper warning: Suspicious cast: there is no type in the solution which is inherited from both 'System.Collections.ObjectModel.ReadOnlyCollection>' and 'MyApp.Program.IMyCollection'
And at runtime, I get an invalid cast exception: Unable to cast object of type 'System.Collections.ObjectModel.ReadOnlyCollection1[System.Collections.Generic.IReadOnlyList1[MyApp.Program+MyObject]]' to type 'IMyCollection'.
OK, I can accept all that. I'm the last person to ask about stuff like covariance and contravariance and stuff like that. But surely there's a way to define and create an object with a short name to stand in for a really long named datatype.
How can I create a type with a really long name and cast to a type with a really short name?
UPDATE:
A co-worker suggested using a using statement.
using IMyCollection= System.Collections.Generic.IReadOnlyList<System.Collections.Generic.IReadOnlyList<MyApp.Program.MyObject>>;
While that would work, it then becomes necessary to do that in every file that uses IMyCollection. Not exactly what I would consider a solution to my goal.
How badly do you want this?
You can manually implement your own wrapper class.
public interface IMyCollection : IReadOnlyList<IReadOnlyList<MyObject>>
{
}
public class MyCollectionImpl : IMyCollection
{
private readonly IReadOnlyList<IReadOnlyList<MyObject>> _wrappedCollection;
public MyCollectionImpl(IReadOnlyList<IReadOnlyList<MyObject>> wrappedCollection)
{
_wrappedCollection = wrappedCollection;
}
public int Count
{
get
{
return _wrappedCollection.Count;
}
}
public IReadOnlyList<MyObject> this[int index]
{
get
{
return _wrappedCollection[index];
}
}
public IEnumerator<IReadOnlyList<MyObject>> GetEnumerator()
{
return _wrappedCollection.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return _wrappedCollection.GetEnumerator();
}
}
Then you simply create an instance of this:
public class MyObject
{
public static IMyCollection GetCollection()
{
var a = new List<MyObject>();
a.Add(new MyObject());
var b = new List<IReadOnlyList<MyObject>>();
b.Add(a.AsReadOnly());
return new MyCollectionImpl(b.AsReadOnly());
}
}
This seems like a lot of extra work, but I would actually consider this a refactoring step.
I believe that the need to pass around types made up of complex set of generic parameters, is actually a bad smell in your code.
Ask yourself, what are you actually using IMyCollection for? Would you be able to add some specialized methods to this interface to make it easier to use?
Once you've created your own MyCollectionImpl class you can slowly add a number of methods to your IMyCollection interface to simplify it's usage. At some point, you might even get to the stage where you can stop exposing the <IReadonlyList<IReadonlyList<MyObject>> interface.
This has nothing to do with covariance. IMyCollection inherits from IReadOnlyList<IReadOnlyList<MyObject>> so you can cast an instance of IMyCollection to IReadOnlyList<IReadOnlyList<MyObject>> but not the other way around.
If you wanna have some custom conversions then you can create a type instead with the short name you want and declare a conversion from IReadOnlyList<IReadOnlyList<MyObject>> to your type using operator overloading. This really seems unnecessary and unusual way to use operator overloading but it's the only way to do what you want to achieve.

Casting one generic to another, without class constraints

I have the following code:
public interface IDrilldown
{
void AddCriteria<T>(T Criterion);
}
public class MyClass<W> : IDrilldown // where W : class
{
void IDrilldown.AddCriteria<T>(T Criterion)
{
W value = Criterion as W;
...
}
}
Unfortunately, the cast I have above will not work unless W has the constaint in the code. I would like to have this using value types. Is it at all possible?
I cannot make W and T the same type. My interface does not have a type associated with it globally, only the internal data types.
This is so that I can have a List all having different T's
I was able to find a way to do it, it's a little hacky but allows it to work:
class MyClass<W> : IDrilldown {
void IDrilldown.AddCriteria<T>(T Criterion) {
if (Criterion is W) {
W value = (W)Convert.ChangeType(Criterion, typeof(W));
// value is W, have fun
// or - as Snowbear pointed out in the comments
W value = (W)(object)Criterion;
// works just as well....
} else {
// value is NOT W and could not be converted.
}
}
}
The only drawback with this is, Convert.ChangeType will use converters to change between internal objects, so string value = (string)Convert.ChangeType(1, typeof(string)) will work and return "1" instead of throwing an exception.
To clarify on how this works, the documentation states:
For the conversion to succeed, value must implement the IConvertible interface, because the method simply wraps a call to an appropriate IConvertible method. The method requires that conversion of value to conversionType be supported.
so for this method to work with custom types you will need to implement the IConvertible interface to convert from one custom type to any other type. In the code sample above, if both T and W are the same type, the Convert.ChangeType will succeed, even if the custom object does not implement IConvertiable.
Would the dynamic keyword help you out?
Something like this:
public interface IDrilldown
{
void AddCriteria<T>(T Criterion);
}
public class MyClass : IDrilldown
{
void IDrilldown.AddCriteria<T>(T criterion)
{
dynamic value = criterion;
// can use typeof() to figure out type if needed...
...
}
}

Why it is not possible to define generic indexers in .NET?

Why can't you create a generic indexer in .NET?
the following code throws a compiler error:
public T this<T>[string key]
{
get => /* Return generic type T. */
}
Does this mean you can't create a generic indexer for a generic member collection?
Here's a place where this would be useful. Say you have a strongly-typed OptionKey<T> for declaring options.
public static class DefaultOptions
{
public static OptionKey<bool> SomeBooleanOption { get; }
public static OptionKey<int> SomeIntegerOption { get; }
}
Where options are exposed through the IOptions interface:
public interface IOptions
{
/* since options have a default value that can be returned if nothing's
* been set for the key, it'd be nice to use the property instead of the
* pair of methods.
*/
T this<T>[OptionKey<T> key]
{
get;
set;
}
T GetOptionValue<T>(OptionKey<T> key);
void SetOptionValue<T>(OptionKey<T> key, T value);
}
Code could then use the generic indexer as a nice strongly-typed options store:
void Foo()
{
IOptions o = ...;
o[DefaultOptions.SomeBooleanOption] = true;
int integerValue = o[DefaultOptions.SomeIntegerOption];
}
I don't know why, but indexers are just syntactic sugar. Write a generic method instead and you'll get the same functionality. For example:
public T GetItem<T>(string key)
{
/* Return generic type T. */
}
Properties can't be generic in C#2.0/3.0 so therefore you can't have a generic indexer.
You can; just drop the <T> part from your declaration and it will work fine. i.e.
public T this[string key]
{
get { /* Return generic type T. */ }
}
(Assuming your class is generic with a type parameter named T).
The only thing I can think of this can be used is something along these lines:
var settings = ConfigurationSection.AppSettings;
var connectionString = settings<string>["connectionString"];
var timeout = settings<int>["timeout"];
But this doesn't actually buy you anything. You've just replaced round parentheses (as in (int)settings["timeout"]) with angle brackets, but received no additional type safety as you can freely do
var timeout = settings<int>["connectionString"];
If you have something that's strongly but not statically typed, you might want to wait until C# 4.0 with its dynamic keyword.
I like the ability to have an indexer without handing out
a direct reference to the "indexed" item. I wrote a simple
"call back" Indexer class below ...
R = the returned type from the indexer
P = the passed type into the indexer
All the indexer really does is pass the operations to
the deployer and allow them to manage what actually occurs
and gets returned.
public class GeneralIndexer<R,P>
{
// Delegates
public delegate R gen_get(P parm);
public delegate void gen_set(P parm, R value);
public delegate P[] key_get();
// Events
public event gen_get GetEvent;
public event gen_set SetEvent;
public event key_get KeyRequest;
public R this[P parm]
{
get { return GetEvent.Invoke(parm); }
set { SetEvent.Invoke(parm, value); }
}
public P[] Keys
{
get
{
return KeyRequest.Invoke();
}
}
}
To use it in a program or class:
private GeneralIndexer<TimeSpan, string> TimeIndex = new GeneralIndexer<TimeSpan,string>();
{
TimeIndex.GetEvent += new GeneralIndexer<TimeSpan, string>.gen_get(TimeIndex_GetEvent);
TimeIndex.SetEvent += new GeneralIndexer<TimeSpan, string>.gen_set(TimeIndex_SetEvent);
TimeIndex.KeyRequest += new GeneralIndexer<TimeSpan, string>.key_get(TimeIndex_KeyRequest);
}
works like a champ especially if you want to monitor access to
your list or do any special operations when something is accessed.
In recent C-sharp you can declare the return type as "dynamic". This is the same as using "object" except that the C# runtime will allow you to use it in code as if it was the type you think it is and then check at run-time to be sure you were right...

Generics in c# & accessing the static members of T

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()
}

Categories