Why do C# out generic type parameters violate covariance? - c#

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.

Related

C# Passing a Generic Class As a Method Parameter

I have a CreateMessage class that is meant to handle incoming messages from a TCPClient, get the user type and return how the message should be formatted to its calling method.
In the method GetUserType, I want to pass UserBaseType as a parameter, which is a generic abstract class that takes a Type of UserType. However, it gives me the error:
Using the generic type 'UserTypeBase' requires one type argument.
I'm still trying to wrap my head around using generics and constraints, so I don't know if I'm going about this the wrong way. I've done a bit of digging to try to find a solution myself, but haven't found anything that more or less tailors to what I'm trying to do.
internal class CreateMessage
{
internal static string user;
internal static string message;
internal CreateMessage(string data)
{
user = Lists.users[data.Substring(1, 3)];
message = data.Substring(5, data.Length - 5);
}
private UserType GetUserType(UserTypeBase type)
{
return type.CreateType();
}
internal string Message()
{
UserType Type = null;
if (user.Contains("[M]"))
Type = GetUserType(UserMod);
else if (user.Contains("[B]"))
Type = GetUserType(UserVIP);
else
Type = GetUserType(UserRegular);
return Type.Message();
}
}
UserBaseType.cs
internal abstract class UserTypeBase<T> where T: UserType
{
public abstract string User { get; }
public abstract string Message { get; }
public abstract T CreateType();
}
You're going to want to make the method that takes the parameter generic as well. You're going to also want to mirror the type constraints as they appear on the parametric type to avoid compilation errors, as well as be explicit in what is and is not acceptable for the method.
private T GetUserType<T>(UserTypeBase<T> type) where T : UserType
{
return type.CreateType();
}
You can then call it with the type provided explicitly or implicitly, depending on the situation.
var someType = new UserTypeDerived<UserType>();
var resultImplicit = GetUserType(someType);
var resultExplicit = GetUserType<UserType>(someType);
Since it's a parameter that is being used generically, the compiler can implicitly determine what the expected value of T is based on the type of the parameter supplied.

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.

Can I use templates dynamically?

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

Passing Delegate object to method with Func<> parameter

I have a method Foo4 that accepts a parameter of the type Func<>. If I pass a parameter of anonymous type , I get no error. But if I create and pass an object of the type 'delegate' that references to a Method with correct signature, I get compiler error. I am not able to understand why I am getting error in this case.
class Learn6
{
delegate string Mydelegate(int a);
public void Start()
{
Mydelegate objMydelegate = new Mydelegate(Foo1);
//No Error
Foo4(delegate(int s) { return s.ToString(); });
//This line gives compiler error.
Foo4(objMydelegate);
}
public string Foo1(int a) { return a.ToString();}
public void Foo4(Func<int, string> F) { Console.WriteLine(F(42)); }
}
It works if you pass a reference to the method directly:
Foo4(Foo1);
This is because actual delegates with the same shape are not inherently considered compatible. If the contracts are implicit, the compiler infers the contract and matches them up. If they are explicit (e.g. declared types) no inference is performed - they are simply different types.
It is similar to:
public class Foo
{
public string Property {get;set;}
}
public class Bar
{
public string Property {get;set;}
}
We can see the two classes have the same signature and are "compatible", but the compiler sees them as two different types, and nothing more.
Because Func<int, string> and MyDelegate are different declared types. They happen to be compatible with the same set of methods; but there is no implicit conversion between them.
//This line gives compiler error.
Foo4(objMydelegate);
//This works ok.
Foo4(objMydelegate.Invoke);
depends on the scenario, but in the general case there's no reason to keep around the Mydelegate type, just use Func<int, string> everywhere :)

Categories

Resources