I'm writing an abstract wrapper for enum in C # (I want something like enum in Vala). My code is:
public abstract class Wraper<T, TE>
where T : Wraper<T, TE>, new()
{
public TE Value;
public static implicit operator T(TE value)
{
return new T() { Value = value };
}
public static implicit operator TE(T value)
{
return value.Value;
}
}
I want to do with something like this:
public enum EFoo { A, B, C, D, E};
public class Foo : Wraper<Foo, EFoo>
{
public bool IsBla
{
get { return Value == EFoo.A || Value == EFoo.E; }
}
}
...
Foo foo = EFoo.A;
bool bla = foo.IsBla;
But the code does not compile because C # does not allow both generic parameter,. When compile reports an error:
User-defined conversion must convert to or from the enclosing type
On line
public static implicit operator T(TE value)
Is there any work around or in C# is not so simple?
The implicit operator must convert either from or to the class you are defining it in. Since you are trying to define it in the abstract base class, it can only convert from or to that class.
The line Foo foo = EFoo.A; does not work because you can't define that conversion in your abstract class, you can only define it in your Foo class.
If you changed your code, as I did below, to convert from/to the base class, the implicit conversions work but you don't get the result you want. Wraper<Foo,EFoo> foo2 = EFoo.A; works because it can be defined in the base class.
Your best bet is probably to use the initializer syntax when creating your foo Foo foo = new Foo { Value = EFoo.A }; or to create some generic conversion functions.
public abstract class Wraper<T, TE>
where T : Wraper<T, TE>, new()
{
public TE Value;
public static implicit operator TE(Wraper<T, TE> value)
{
return value.Value;
}
public static implicit operator Wraper<T, TE>(TE value)
{
return new T { Value = value };
}
}
public enum EFoo
{
A,
B,
C,
D,
E
}
public class Foo : Wraper<Foo, EFoo>
{
public bool IsBla
{
get
{
return Value == EFoo.A || Value == EFoo.E;
}
}
}
Related
I am trying to write an Alias class which enables me to:
int n = new Count(1);
That is, it encapsulates an int in this case as a Count, which gives some type safety and domain meaning, while it automatically converts back to the underlying type.
With non-nullable reference types, I have another issue. I cannot figure out how to handle both of these scenarios at the same time:
int someCount = new Count(1);
Count? nothing = null;
int? noCount = nothing;
This happens because I have types like this:
record Device(Count Cpu, Count? Cores); // Contrived example
Seems like the problem is I cannot overload an operator with both nullable and non-nullable version of the same type:
record Alias<T>(T Value)
{
public static implicit operator T(Alias a) => a.Value;
public static implicit operator T?(Alias? a) => null;
}
record Count : Alias<int> { /**/ }
The point is, if I have a null, I want it converted to null of the target type.
If you don't have any Aliases that wraps reference types, then I think the best thing to do here is to just limit T here to structs. After that, T, and T? become distinct types, allowing you to create two operators:
record Alias<T>(T Value) where T: struct
{
public static implicit operator T?(Alias2<T>? a) => a?.Value;
public static implicit operator T(Alias2<T> a) => a.Value;
}
If you also need to wrap reference types as well, you could consider adding another Alias type that works just for reference types:
record AliasClass<T>(T Value) where T: class
{
[return: NotNullIfNotNull("a")]
public static implicit operator T?(AliasClass<T>? a) => a?.Value;
}
record AliasStruct<T>(T Value) where T: struct
{
public static implicit operator T?(AliasStruct<T>? a) => a?.Value;
public static implicit operator T(AliasStruct<T> a) => a.Value;
}
Then you can have for example:
record Count(int Value) : AliasStruct<int>(Value) { /**/ }
record StringWrapper(string Value) : AliasClass<string>(Value) { /**/ }
As commented, it's not possible to overload an operator with both nullable and non-nullable generic types.
I kind of solved it with extension methods:
public static class AliasClass
{
public static V? Unwrap<V, A>(this Alias<V, A>? a)
where A : Alias<V, A> where V : class => a?.Value;
}
public static class AliasStruct
{
public static V? Unwrap<V, A>(this Alias<V, A>? a)
where A : Alias<V, A> where V : struct => a?.Value;
}
[SuppressMessage("ReSharper", "VirtualMemberCallInConstructor")]
public abstract record Alias<V, A> where A : Alias<V, A>
{
protected Alias(V value)
{
Value = value;
EnsureValid(Value);
}
public V Value { get; }
protected virtual void EnsureValid(V value) { }
public override sealed string ToString() => Value?.ToString() ?? "";
public static implicit operator V(Alias<V, A> a) => a.Value;
}
Usage:
int a = new Count(1);
int? n = new Count(2).Unwrap();
The symmetry, sadly, is broken. I can't find a way to implement Unwrap() for the non-nullable case.
I'm troubleshooting a problem that I have recreated in a solution here.
The issue is that I am using some custom types that can implicitly cast from string to themselves. One of the custom types inherits from the other.
public class CustomType
{
public string InnerString { get; protected set; }
public CustomType(string s)
{
InnerString = s;
}
#region Operator Overloads
public static implicit operator CustomType(string s)
{
if (s == null)
throw new ArgumentNullException();
return new CustomType(s);
}
public static implicit operator string(CustomType value)
{
if (value == null)
return null;
return value.InnerString;
}
#endregion
}
public class SubCustomType : CustomType
{
public SubCustomType(string s)
: base(s)
{
// Nada
}
#region Operator Overloads
public static implicit operator SubCustomType(string s)
{
if (s == null)
throw new ArgumentNullException();
return new SubCustomType(s);
}
public static implicit operator string(SubCustomType value)
{
if (value == null)
return null;
return value.InnerString;
}
#endregion
}
In another generic class, I rely upon the fact that the base custom type can implicitly cast from string to itself. (The cast occurs at the line (T)this.Rtf. .Rtf is a string.) (The generic class is in my case a subclass of RichTextBox, since that's what I was using when I ran into this problem.)
public class CustomRichTextBox<T> : Forms.RichTextBox
where T : CustomType
{
public object GetValue()
{
/// This line throws:
/// InvalidCastException
/// Unable to cast object of type 'TestCustomTypesCast.CustomType' to type 'TestCustomTypesCast.SubCustomType'.
return (T)this.Rtf;
}
}
public class SubCustomRichTextBox : CustomRichTextBox<SubCustomType>
{
}
When I use SubCustomRichTextBox (an instance of the generic class that has as type argument the SUB custom type), I get an InvalidCastException at the line where I cast to T in GetValue. What I think is going on is that in order for the compiler to be okay with the fact that I am using T to cast from string, it is looking at CustomType and seeing its cast overload. But even when I use a subclass of CustomType as the actual type argument, the compiler still looks to SubCustomType.CustomType(string s) to perform the cast, and not at the correct SubCustomType.SubCustomType(string s) method.
Can anyone point me in the direction of fixing this problem? I want to use the generic class because it would allow me to reuse the same code. If I can't use generics, then I'll need to duplicate code in several subclasses of CustomRichTextBox<T>. Thanks.
It's going to be hard because the operator overload is static, and you're essentially trying to get a virtual behaviour.
Try this:
public class CustomRichTextBox<T> : Forms.RichTextBox
where T : CustomType, new()
{
public object GetValue()
{
T t = new T();
t.InnerString = this.Rtf;
return t;
}
}
Note I've added new() to the type constraint. I also had to make InnerString public settable.
As an aside, you coule make the return type of GetValue() be T. That might be a nicer API.
I have a generics class that I used to write data to IsolatedStorage.
I can use an static implicit operator T() to convert from my Generic class to the Generic Parameter T
e.g.
MyClass<double> foo = new MyClass(187.0);
double t = foo;
My question is, how can I do the reverse?
MyClass<double> foo = new MyClass(187.0);
double t = 0.2d;
foo = t;
The implicit operator has to be static, so I'm not sure how I can pass in the instance of my class?
This class shows conversion between T and MyClass, both ways.
class MyClass<T>
{
public MyClass(T val)
{
Value = val;
}
public T Value { get; set; }
public static implicit operator MyClass<T>(T someValue)
{
return new MyClass<T>(someValue);
}
public static implicit operator T(MyClass<T> myClassInstance)
{
return myClassInstance.Value;
}
}
EDIT:
If you want to be able to change the value of T in your class, I would recommend exposing it as a property like:
T Value { get; set; }
That will allow you to change the value, instead of the behavior of the implicit operator returning an entirely new instance of the class.
You can and can't using implicit operators. Doing something like
public static implicit operator int(MyType m)
public static implicit operator MyType(int m)
will implicitly convert from MyType to int and from int to MyType respectively. However, you're right, since they are static, the int to MyType specifically will have to create a new instance of MyType and return that.
So this code:
MyClass<double> foo = new MyClass(187.0);
double t = 0.2d;
foo = t;
wouldn't replace the value in foo with t, the implicit operator would return an entirely new MyClass from t and assign that to Foo.
You should be able to convert the other way by simply specifying another implicit operator:
public static implicit operator MyClass<T>(T input)
{
return new MyClass<T>(input);
}
I'm sure this is a stupid question, but why does the following code not call the explicit operator for the cast on the child class MyBool?
public class DataType
{
public static explicit operator bool(DataType D)
{
return false;
}
public static explicit operator DataType(bool B)
{
return new DataType();
}
}
public class MyBool : DataType
{
public bool Value;
public MyBool()
{
Value = false;
}
public static explicit operator bool(MyBool B)
{
return B.Value;
}
public static explicit operator MyBool(bool B)
{
return new MyBool() { Value = B };
}
}
then:
List<DataType> Types = new List<DataType>();
Types.Add(new MyBool() { Value = true });
Types.Add(new MyBool() { Value = false });
foreach (DataType T in Types)
{
bool Value = (bool)T;
MessageBox.Show(Value.ToString());
}
Produces the output: false, false
Is my only option to write functions on each class to take the place of the explicit operator functions?
why does the following code not call the explicit operator for the cast on the child class MyBool?
Because the operator functions are static, hence also non-virtual and thus their target is resolved at compile time rather than runtime. This is the expected behaviour.
If you want to have polymorphic conversion operators you can call virtual functions inside the operators:
public abstract class DataType
{
public static explicit operator bool(DataType D)
{
return D.DoCastToBool();
}
public static explicit operator DataType(bool B)
{
// We haven’t got an instance of our class here.
// You can use a factory method pattern to emulate virtual constructors.
}
protected abstract bool DoCastToBool();
}
Operators are overloaded rather than overridden - in other words, the choice about which implementation to use is made at compile-time. The compiler only knows about T as DataType, so it calls the operator in DataType.
One option would be to remove the operator from MyBool, but add a virtual method in DataType, allowing for polymorphic behaviour:
public class DataType
{
public static explicit operator bool(DataType D)
{
// TODO: Decide how you want to handle null references
return D.ToBoolean();
}
protected virtual bool ToBoolean()
{
return false;
}
}
public class MyBool : DataType
{
// ...
protected override bool ToBoolean()
{
return Value;
}
}
Note that this won't work for the conversion from bool to a DataType, as in that case we don't have any information about which subtype of DataType you actually want to create.
(Side-note: your code would be easier to follow if you used the normal .NET naming conventions.)
Here's a garbage solution for you:
replace: bool Value = (bool)T;
with: bool Value = (bool)(T as MyBool);
Consider the following code:
class CustomClass
{
public CustomClass(string value)
{ m_value = value; }
public static bool operator ==(CustomClass a, CustomClass b)
{ return a.m_value == b.m_value; }
public static bool operator !=(CustomClass a, CustomClass b)
{ return a.m_value != b.m_value; }
public override bool Equals(object o)
{ return m_value == (o as CustomClass).m_value; }
public override int GetHashCode()
{ return 0; /* not needed */ }
string m_value;
}
class G
{
public static bool enericFunction1<T>(T a1, T a2) where T : class
{ return a1.Equals(a2); }
public static bool enericFunction2<T>(T a1, T a2) where T : class
{ return a1==a2; }
}
Now when I call both generic functions, one succeeds and one fails:
var a = new CustomClass("same value");
var b = new CustomClass("same value");
Debug.Assert(G.enericFunction1(a, b)); // Succeeds
Debug.Assert(G.enericFunction2(a, b)); // Fails
Apparently, G.enericFunction2 executes the default operator== implementation instead of my override. Can anybody explain why this happens?
From Constraints on Type Parameters (C# Programming Guide):
When applying the where T : class constraint, avoid the == and != operators on the type parameter because these operators will test for reference identity only, not for value equality. This is the case even if these operators are overloaded in a type that is used as an argument. (...) The reason for this behavior is that, at compile time, the compiler only knows that T is a reference type, and therefore must use the default operators that are valid for all reference types.
If I change the enericFunction2 to:
public static bool enericFunction2<T>(T a1, T a2) where T : class
{
object aa = a1;
CustomClass obj1 = (CustomClass)aa;
object bb = a2;
CustomClass obj2 = (CustomClass)bb;
return obj1 == obj2;
}
Then everything works fine. But I am afraid I can't explain it. I mean a1 and a2 know their type. Why a cast is needed to the CustomClass, so the operators are called?