Can I use templates dynamically? - c#

I have a class:
class abc <T> {
private T foo;
public string a {
set {
foo = T.parse(value);
}
get{
return foo.toString();
}
}
}
However the T.parse command is giving me an error. Anyone of a way to do what I am trying to do?
I am using this as a base class for some other derived classes.
Edit:
What I ended us doing:
Delegate parse = Delegate.CreateDelegate(typeof(Func<String, T>), typeof(T).GetMethod("Parse", new[] { typeof(string) }));
I do that once in the constructor
and then I do the following in my property:
lock (lockVariable)
{
m_result = (T)parse.DynamicInvoke(value);
dirty = true;
}

C# generic types are not C++ templates. A template lets you do a fancy "search and replace" where you would substitute the name of a type that implements a static parse method for T. C# generics are not a textual search-and-replace mechanism like that. Rather, they describe parameterized polymorphism on types. With a template, all that is required is that the specific arguments you substitute for the parameters are all good. With a generic every possible substitution whether you actually do it or not, has got to be good.
UPDATE:
A commenter asks:
What would be the C# way of doing things when an equivalent to Haskell's Read type class is needed?
Now we come to the deep question underlying the original question.
To clarify for the reader unfamiliar with Haskell: Since C# 2.0, C# has supported "generic" types, which are a "higher" kind of type than regular types. You can say List<int> and a new type is made for you that follows the List<T> pattern, but it is a list specifically of integers.
Haskell supports an even higher kind of type in its type system. With generic types you can say "every MyCollection<T> has a method GetValue that takes an int and returns a T, for any T you care to name". With generic types you can put constraints on T and say "and furthermore, T is guaranteed to implement IComparable<T>..." With Haskell typeclasses you can go even further and say the moral equivalent of "...and moreover, T is guaranteed to have a static method Parse that takes a string and returns a T".
The "Read" typeclass is specifically that typeclass that declares the moral equivalent of "a class C that obeys the Read typeclass pattern is one that has a method Parse that takes a string and returns a C".
C# does not support that kind of higher type. If it did then we could typecheck patterns in the language itself such as monads, which today can only be typechecked by baking them into the compiler (in the form of query comprehensions, for example.) (See Why there is no something like IMonad<T> in upcoming .NET 4.0 for some more thoughts.)
Since there is no way to represent that idea in the type system, you're pretty much stuck with not using generics to solve this problem. The type system simply doesn't support that level of genericity.
People sometimes do horrid things like:
static T Read<T>(string s)
{
if (typeof(T) == typeof(int)) return (T)(object)int.Parse(s);
if ...
but that is in my opinion a bit abusive; it really is not generic.

You could use reflection. You cannot access static members through a generic parameter.
class Abc<T> {
private T foo;
public string a {
set {
foo = Parse<T>(value);
}
get {
return foo.ToString();
}
}
static T Parse<T>(string s)
{
var type = typeof(T);
var method = type.GetMethod("Parse", new[] { typeof(string) });
return (T)method.Invoke(null, new[] { s });
}
}

C# doesn't have templates. .NET generics don't work like C++ templates.
With an appropriate constraint, you can use instance methods on parameters with generic type, but there's no way to constrain static members.
However, you could use reflection, something along the lines of typeof(T).GetMethod("Parse"), to make a Func<string,T> delegate.

T.parse is not known in the generic parameter. You have to make it known.
dont use reflection. Its slow and generally a bad solution in this case.
use generics in a correct way.
You have to specify that T can be only classes which implement an interface which contains a parse method:
class abs<T> where T : IParsable<T>
{
//your implementation here
}
interface IParsable<T>
{
T Parse(string value);
}
public class Specific : IParsable<Specific>
{
public Specific Parse(string value)
{
throw new NotImplementedException();
}
}

You can't call a static method on a generic class.
Look at this post: Calling a static method on a generic type parameter
But here is a little workaround:
public interface iExample
{
iExample Parse(string value);
}
class abc<T> where T : iExample, new()
{
private T foo;
public string a
{
set
{
foo = (T)(new T().Parse(value));
}
get
{
return foo.ToString();
}
}
}
So if you have an class that implements iExample
public class SelfParser : iExample
{
public iExample Parse(string value)
{
return new SelfParser();
}
}
You will be able to use it like this:
abc<SelfParser> abcInstance = new abc<SelfParser>();
abcInstance.a = "useless text";
string unParsed = abcInstance.a; // Will return "SelfParser"

While you can't do exactly that with Generics (there are no type constraints for that enforce a specific method signature, only struct/object/interface constraints).
You can create a base class whose constructor takes the Parse method. See my Int32 implementation at the bottom.
class MyParseBase <T>
{
public MyBase (Func<string,T> parseMethod)
{
if (parseMethod == null)
throw new ArgumentNullException("parseMethod");
m_parseMethod = parseMethod;
}
private T foo;
public string a {
set
{
foo = m_parseMethod(value);
}
get
{
return foo.toString();
}
}
}
class IntParse : MyParseBase<Int32>
{
public IntParse()
: base (Int32.Parse)
{}
}

This is a variation on Oleg G's answer which removes the need for the new() type constraint. The idea is you make a Parser for each type you want to be contained in an abs, and inject it - this is a formalization of the Func<string, T> approach as well.
interface IParser<T>
{
T Parse(string value);
}
class abs<T>
{
private readonly IParser<T> _parser;
private T foo;
public abs(IParser<T> parser)
{
_parser = parser;
}
public string a {
set
{
foo = _parser.Parse(value);
}
get
{
return foo.ToString();
}
}

class abc<T> {
private T foo;
public string a {
set {
var x_type = typeof(T);
foo = (T)x_type.InvokeMember("Parse", System.Reflection.BindingFlags.InvokeMethod, null, value, new []{value});
}
get{
return foo.ToString();
}
}
}

Related

Generic class where type can Parse strings

I want to create a generic class where the type of the class can Parse strings.
I want to use this class for any class that has a static function Parse(string),
like System.Int32, System.Double, but also for classes like System.Guid. They all have a static Parse function
So my class needs a where clause that constraints my generic type to types with a Parse function
I'd like to use it like this:
class MyGenericClass<T> : where T : ??? what to do ???
{
private List<T> addedItems = new List<T>()
public void Add(T item)
{
this.AddedItems.Add(item);
}
public void Add(string itemAsTxt)
{
T item = T.Parse(itemAsTxt);
this.Add(item);
}
}
What to write in the where clause?
I was not happy with the answers that would use reflection to do the Parsing.
I prefer a solution that is type safe, so the compiler would complain about the a missing Parse function.
Normally you would constraint to a class that has an interface. But as others said, there is no common interface. Come to think of it I don't need an interface, I need a function that I can call
So my solution would be to insist that creators would provide a delegate to the Parse Function that would parse a string to type T
class MyGenericClass<T>
{
public MyGenericClass(Func<string, T> parseFunc)
{
this.parseFunc = parseFunc;
}
private readonly Func<string, T> parseFunc;
public void Add(string txt)
{
this.Add(parseFunc(txt));
}
}
Usage:
MyGenericClass<Guid> x = new MyGenericClass<Guid>(txt => Guid.Parse(txt));
MyGenericClass<int> y = new MyGenericClass<int> (txt => System.Int32.Parse(txt));
The answer is simpler than I thought
I might be misunderstanding your question, but will this do the trick?
static void Main(string[] args)
{
Guid g = DoParse<Guid>("33531071-c52b-48f5-b0e4-ea3c554b8d23");
}
public static T DoParse<T>(string value)
{
T result = default(T);
MethodInfo methodInfo = typeof(T).GetMethod("Parse");
if (methodInfo != null)
{
ParameterInfo[] parameters = methodInfo.GetParameters();
object classInstance = Activator.CreateInstance(typeof(T), null);
object[] parametersArray = new object[] { value };
result = (T)methodInfo.Invoke(methodInfo, parametersArray);
}
return result;
}
You can´t do that at compile-time at all. All those methods don´t have anything in common except their names. They neither are defined in any common interface nor have they the same parameters.
Imagine you have your own method that accidently has that name, but does something completely different. In addition it´s also an instance-method:
class MyType
{
void Parse() { ... }
}
As you can see that method don´t even has any argument, making it hard to find any common logic between - say - int.Parse(myString)andmyInstanceOfMyType.Parse()`.
But even if you could do that. What would you do with the item? There´s not much as there´s nothing in common between them. In particular it´s impossible to call the methpd, as they are completely different.
You could loop all types with a similar method at runtime however:
var types = allAssemblies.SelectMany(x => x.GetTypes())
.Where(x => x.GetMethod("Parse") != null);
But be aware that this yields to an AmbiguousMatchException if more than one method per type exists with the name, this is when the method is overloaded.

C# generic supertype wildcard

I got a problem with wildcards in generics in C#. First approach to get my little example running was to use object as generic type because it is the base class of everything.
public class AttributeManager
{
private Dictionary<int, AttributeItem<object>> attributes = new Dictionary<int, AttributeItem<object>>();
public void add(AttributeItem<object> attribute)
{
if (hasAttribute(attribute)) {
return;
}
attributes.Add(attribute.getKey(), attribute);
}
}
public abstract class AttributeItem<T>
{
private int key;
private T attributeValue;
private AttributeManager attributeManager;
public AttributeItem(AttributeManager attributeManager, int key)
{
this.key = key;
this.attributeManager = attributeManager;
attributeManager.add(this); // this line does not work
}
public void setValue(T newValue)
{
attributeValue = newValue;
}
public T getValue()
{
return attributeValue;
}
}
However, the line:
attributeManager.add(this);
does not work. It says there was no overloaded method found for this call. I thought that "this" will get casted to AttributeItem because object must be superclass of T.
So my first question is why does this cast does not work?
My second approach was to change the AttributeManager to use kind of wildcards:
public class AttributeManager
{
private Dictionary<int, AttributeItem<????>> attributes = new Dictionary<int, AttributeItem<????>>();
/**
* This method will add a new AttributeItem if hasAttribute(AttributeItem) returns false.
*/
public void add<T>(AttributeItem<T> attribute)
{
if (hasAttribute(attribute)) {
return;
}
attributes.Add(attribute.getKey(), attribute); // this line fails
}
}
But as you can see, I have no clue what type I have to pass in the declaration:
Dictionary<int, AttributeItem<????>> attributes
So my second question is, what do I have to use instead of ?????
Regards
Robert
The most simple solution is to get rid of generics at the level of your private dictionary field:
private Dictionary<int, object> attributes = new Dictionary<int, object>();
That way your class still has a nice generic interface and you don't need to have a generic Manager instance.
The difficult part is getting something useful out of the dictionary later on. You could use reflection, but I suggest you use the interface technique as suggested by Onam and Robert Hahn. Tell us more about your usecase, if this does not solve your issue.
You should have something like this:
public class AttributeManager<T>
{
private Dictionary<int, AttributeItem<T>> attributes = new Dictionary<int, AttributeItem<T>>();
public void add(AttributeItem<T> attribute)
{
if (hasAttribute(attribute)) {
return;
}
attributes.Add(attribute.getKey(), attribute);
}
}
However, the line:
attributeManager.add(this);
does not work. It says there was no overloaded method found for this call. I thought that > "this" will get casted to AttributeItem because object must be superclass of T
You need to read about covariance and contravariance. Basically, just because T is convertible to a base type doesn't meant a generic interface is. It all depends on what the interface is used for.
In your case, T is an input parameter, so it cannot be contravariant (enabling the AttributeItem cast). Otherwise, the compile-time contract would allow object to be passed to setValue, which is not a valid substitution.
Depending on what you need to do with AttributeItem, you may be able to define a contravariant interface with just the needed generic return values for AttributeManager.

How can I call a method from a Template?

I have this C# WinForms code in which I have several different structs, that all function in the same way. So instead of writing individual functions for adding or removing items, I'm trying to use Templates instead.
For example, here is one struct and the corresponding List<> I'm using to store its objects:
public struct Alias
{
public string alias;
public string aliasSource;
public static bool IsValid(...); //This function exists in all the structs
};
List<Alias> aliases;
This the function used from the outside, to add Aliases:
public void AddAlias(Alias iAlias)
{
AddGenericStructItem<Alias>(iAlias, aliases);
}
And this is the actual function doing the addition:
private void AddGenericStructItem<T>(T genericStructItem, List<T> genericList)
{
string outputError;
if (T.IsValid(genericStructItem, out outputError)) //< -- Problem in the 'T' being used in the far left
{
if (genericList.Contains(genericStructItem))
{
MessageBox.Show("ERROR 82ha5jb :: Item already exists");
}
else
{
genericList.Add(genericStructItem);
}
}
else
{
MessageBox.Show(outputError);
}
}
The problem occurs in the T.IsValid... part. The compiler gives me the following error on the T:
'T' is a 'type parameter', which is not valid in the given context
Is there any way around this? All my structs have an IsValid function in them with the same setup, so it would seem silly to repeatedly write the same code, in case I don't use templates here...
You can't do that. The only option is defining where constraint for your generic parameter to be of some interface or base class type. But you can't do this neither with structs nor with static members. If you change your structs to classes, then you can do following:
public interface IValidatable
{
bool IsValid(out outputError);
}
public class Alias : IValidatable
{
public string alias;
public string aliasSource;
public bool IsValid(out outputError) { ... };
};
Now you can apply constraint:
private void AddValidatableItem<T>(T item, List<T> list)
where T : IValidatable
{
string outputError;
if (!item.IsValid(out outputError))
{
MessageBox.Show(outputError);
return;
}
if (list.Contains(item))
{
MessageBox.Show("ERROR 82ha5jb :: Item already exists");
return;
}
list.Add(item);
}
BTW you can take advantage of C# extension methods and make this method an extension of validatable items list:
public static void AddValidatableItem<T>(this List<T> list, T item)
where T : IValidatable
This will allow you to call method on list:
aliases.AddValidatableItem(newAlias);
You can't use constraints to tell the compiler that a static method will exist on your object. If it really needs to be static, you'll need to use reflection to call the method:
var methodInfo = typeof(T).GetMethod("IsValid", BindingFlags.Static|BindingFlags.Public);
if (methodInfo != null)
{
object[] parameters = new object[] { genericStructItem, null };
if ((bool)methodInfo.Invoke(null, parameters))
{
// It's valid!
}
else
{
string error = (string)parameters[1];
}
}
C# generics are significantly different from templates in C++, although the syntax looks similar.
When you say
T.IsValid(genericStructItem, out outputError);
it sounds like you are expecting the compiler to substitute T with Alias to give you
Alias.IsValid(genericStructItem, out outputError);
which is not how generics work. You need to find another way to call IsValid, such as reflection or adding a common interface to your structs.
Also I would strongly consider using classes instead of structs. I don't know your reasons for choosing structs but in general there are several reasons not to use structs, especially if they need to be mutable.

Why do C# out generic type parameters violate covariance?

I'm unclear as to why the following code snippet isn't covarient?
public interface IResourceColl<out T> : IEnumerable<T> where T : IResource {
int Count { get; }
T this[int index] { get; }
bool TryGetValue( string SUID, out T obj ); // Error here?
}
Error 1 Invalid variance: The type parameter 'T' must be invariantly
valid on 'IResourceColl.TryGetValue(string, out T)'. 'T' is
covariant.
My interface only uses the template parameter in output positions. I could easily refactor this code to something like
public interface IResourceColl<out T> : IEnumerable<T> where T : class, IResource {
int Count { get; }
T this[int index] { get; }
T TryGetValue( string SUID ); // return null if not found
}
but I'm trying to understand if my original code actually violates covariance or if this is a compiler or .NET limitation of covariance.
The problem is indeed here:
bool TryGetValue( string SUID, out T obj ); // Error here?
You marked obj as out parameter, that still means though that you are passing in obj so it cannot be covariant, since you both pass in an instance of type T as well as return it.
Edit:
Eric Lippert says it better than anyone I refer to his answer to "ref and out parameters in C# and cannot be marked as variant" and quote him in regards to out parameters:
Should it be legal to make T marked as "out"? Unfortunately no. "out"
actually is not different than "ref" behind the scenes. The only
difference between "out" and "ref" is that the compiler forbids
reading from an out parameter before it is assigned by the callee, and
that the compiler requires assignment before the callee returns
normally. Someone who wrote an implementation of this interface in a
.NET language other than C# would be able to read from the item before
it was initialized, and therefore it could be used as an input. We
therefore forbid marking T as "out" in this case. That's regrettable,
but nothing we can do about it; we have to obey the type safety rules
of the CLR.
Here's the possible workaround using extension method. Not necessarily convenient from the implementor point of view, but user should be happy:
public interface IExample<out T>
{
T TryGetByName(string name, out bool success);
}
public static class HelperClass
{
public static bool TryGetByName<T>(this IExample<T> #this, string name, out T child)
{
bool success;
child = #this.TryGetByName(name, out success);
return success;
}
}
public interface IAnimal { };
public interface IFish : IAnimal { };
public class XavierTheFish : IFish { };
public class Aquarium : IExample<IFish>
{
public IFish TryGetByName(string name, out bool success)
{
if (name == "Xavier")
{
success = true;
return new XavierTheFish();
}
else
{
success = false;
return null;
}
}
}
public static class Test
{
public static void Main()
{
var aquarium = new Aquarium();
IAnimal child;
if (aquarium.TryGetByName("Xavier", out child))
{
Console.WriteLine(child);
}
}
}
It violates covariance because the value provided to output parameters must be of exactly the same type as the output parameter declaration. For instance, assuming T was a string, covariance would imply that it would be ok to do
var someIResourceColl = new someIResourceCollClass<String>();
Object k;
someIResourceColl.TryGetValue("Foo", out k); // This will break because k is an Object, not a String
Examine this little example and you will understand why it is not allowed:
public void Test()
{
string s = "Hello";
Foo(out s);
}
public void Foo(out string s) //s is passed with "Hello" even if not usable
{
s = "Bye";
}
out means that s must be definitely assigned before execution leaves the method and conversely you can not use s until it is definitely assigned in the method body. This seems to be compatible with covariance rules. But nothing stops you from assigning s at the call site before calling the method. This value is passed to the method which means that even if it is not usable you are effectively passing in a parameter of a defined type to the method which goes against the rules of covariance which state that the generic type can only be used as the return type of a method.

Calling a static method on a generic type parameter

I was hoping to do something like this, but it appears to be illegal in C#:
public Collection MethodThatFetchesSomething<T>()
where T : SomeBaseClass
{
return T.StaticMethodOnSomeBaseClassThatReturnsCollection();
}
I get a compile-time error:
'T' is a 'type parameter', which is not valid in the given context.
Given a generic type parameter, how can I call a static method on the generic class? The static method has to be available, given the constraint.
In this case you should just call the static method on the constrainted type directly. C# (and the CLR) do not support virtual static methods. So:
T.StaticMethodOnSomeBaseClassThatReturnsCollection
...can be no different than:
SomeBaseClass.StaticMethodOnSomeBaseClassThatReturnsCollection
Going through the generic type parameter is an unneeded indirection and hence not supported.
To elaborate on a previous answer, I think reflection is closer to what you want here. I could give 1001 reasons why you should or should not do something, I'll just answer your question as asked. I think you should call the GetMethod method on the type of the generic parameter and go from there. For example, for a function:
public void doSomething<T>() where T : someParent
{
List<T> items=(List<T>)typeof(T).GetMethod("fetchAll").Invoke(null,new object[]{});
//do something with items
}
Where T is any class that has the static method fetchAll().
Yes, I'm aware this is horrifically slow and may crash if someParent doesn't force all of its child classes to implement fetchAll but it answers the question as asked.
You can do what I call a surrogate singleton, I've been using it as a sort of "static inheritance" for a while
interface IFoo<T> where T : IFoo<T>, new()
{
ICollection<T> ReturnsCollection();
}
static class Foo<T> where T : IFoo<T>, new()
{
private static readonly T value = new();
public static ICollection<T> ReturnsCollection() => value.ReturnsCollection();
}
// Use case
public ICollection<T> DoSomething<T>() where T : IFoo<T>, new()
{
return Foo<T>.ReturnsCollection();
}
The only way of calling such a method would be via reflection, However, it sounds like it might be possible to wrap that functionality in an interface and use an instance-based IoC / factory / etc pattern.
It sounds like you're trying to use generics to work around the fact that there are no "virtual static methods" in C#.
Unfortunately, that's not gonna work.
I just wanted to throw it out there that sometimes delegates solve these problems, depending on context.
If you need to call the static method as some kind of a factory or initialization method, then you could declare a delegate and pass the static method to the relevant generic factory or whatever it is that needs this "generic class with this static method".
For example:
class Factory<TProduct> where TProduct : new()
{
public delegate void ProductInitializationMethod(TProduct newProduct);
private ProductInitializationMethod m_ProductInitializationMethod;
public Factory(ProductInitializationMethod p_ProductInitializationMethod)
{
m_ProductInitializationMethod = p_ProductInitializationMethod;
}
public TProduct CreateProduct()
{
var prod = new TProduct();
m_ProductInitializationMethod(prod);
return prod;
}
}
class ProductA
{
public static void InitializeProduct(ProductA newProduct)
{
// .. Do something with a new ProductA
}
}
class ProductB
{
public static void InitializeProduct(ProductB newProduct)
{
// .. Do something with a new ProductA
}
}
class GenericAndDelegateTest
{
public static void Main()
{
var factoryA = new Factory<ProductA>(ProductA.InitializeProduct);
var factoryB = new Factory<ProductB>(ProductB.InitializeProduct);
ProductA prodA = factoryA.CreateProduct();
ProductB prodB = factoryB.CreateProduct();
}
}
Unfortunately you can't enforce that the class has the right method, but you can at least compile-time-enforce that the resulting factory method has everything it expects (i.e an initialization method with exactly the right signature). This is better than a run time reflection exception.
This approach also has some benefits, i.e you can reuse init methods, have them be instance methods, etc.
You should be able to do this using reflection, as is described here
Due to link being dead, I found the relevant details in the wayback machine:
Assume you have a class with a static generic method:
class ClassWithGenericStaticMethod
{
public static void PrintName<T>(string prefix) where T : class
{
Console.WriteLine(prefix + " " + typeof(T).FullName);
}
}
How can you invoke this method using relection?
It turns out to be very easy… This is how you Invoke a Static Generic
Method using Reflection:
// Grabbing the type that has the static generic method
Type typeofClassWithGenericStaticMethod = typeof(ClassWithGenericStaticMethod);
// Grabbing the specific static method
MethodInfo methodInfo = typeofClassWithGenericStaticMethod.GetMethod("PrintName", System.Reflection.BindingFlags.Static | BindingFlags.Public);
// Binding the method info to generic arguments
Type[] genericArguments = new Type[] { typeof(Program) };
MethodInfo genericMethodInfo = methodInfo.MakeGenericMethod(genericArguments);
// Simply invoking the method and passing parameters
// The null parameter is the object to call the method from. Since the method is
// static, pass null.
object returnValue = genericMethodInfo.Invoke(null, new object[] { "hello" });
As of now, you can't. You need a way of telling the compiler that T has that method, and presently, there's no way to do that. (Many are pushing Microsoft to expand what can be specified in a generic constraint, so maybe this will be possible in the future).
Here, i post an example that work, it's a workaround
public interface eInterface {
void MethodOnSomeBaseClassThatReturnsCollection();
}
public T:SomeBaseClass, eInterface {
public void MethodOnSomeBaseClassThatReturnsCollection()
{ StaticMethodOnSomeBaseClassThatReturnsCollection() }
}
public Collection MethodThatFetchesSomething<T>() where T : SomeBaseClass, eInterface
{
return ((eInterface)(new T()).StaticMethodOnSomeBaseClassThatReturnsCollection();
}

Categories

Resources