[英]Valid approach for generic operators
I have a class Gen<T>
and I want to make it possible to compare them. 我有一个Gen<T>
类,我希望能够比较它们。 The following code cannot be compiled, because the == cannot be applied to Parent and Child. 以下代码无法编译,因为==无法应用于Parent和Child。 Is there a way to make this comparison possible, or is this bad practice in general? 有没有办法使这种比较成为可能,或者一般来说这是不好的做法?
public class Parent{
public int x;
}
public class Child:Parent{}
public class Gen<T>
where T : Parent
{
public T variable;
}
public static class Gen
{
public static bool operator ==(Gen<Parent> left, Gen<Parent> right){
if (left.variable.x == right.variable.x)
return true;
else
return false;
}
}
public void Test()
{
Gen<Parent> foo = new Gen<Parent>();
Gen<Child> bar = new Gen<Child>();
if (foo == bar)
{
...
}
}
The full context is the following: 完整的上下文如下:
Gen<T>
equals ColorSet<T>
where T:Color Gen<T>
等于ColorSet<T>
,其中T:Color I want to access every Color
through the ColorSet<T>
class, which looks like this: 我想通过ColorSet<T>
类访问每个Color
,如下所示:
public class ColorSet<T> where T : Color
{
private T blue;
private T red;
private T green;
public ColorSet()
{
Red = (T)Activator.CreateInstance(typeof(T), new object[] { });
Red.Name = Values.Res.get("red");
Blue = (T)Activator.CreateInstance(typeof(T), new object[] { });
Blue.Name = Values.Res.get("blue");
Green = (T)Activator.CreateInstance(typeof(T), new object[] { });
Green.Name = Values.Res.get("green");
}
}
But sometimes I need ColorSet<Color>
and sometimes ColorSet<Child>
for the additional information. 但有时候我需要ColorSet<Color>
,有时候需要ColorSet<Child>
来获取更多信息。 And it should be possible to compare ColorSet<Color>
with ColorSet<Child>
because they have the most relevant information in common. 并且应该可以将ColorSet<Color>
与ColorSet<Child>
进行比较,因为它们具有最相关的相关信息。
To come back to your original question/sample: this is not beautifull but it works (for your example - i only tested it with two) It uses reflection though so I'm not that happy with it: 回到你原来的问题/样本:这不是很漂亮,但它有效(对你的例子 - 我只测试了两个)它虽然使用反射,所以我对它不满意:
public class Parent
{
public int x;
public Parent (int x)
{
this.x = x;
}
public override bool Equals(object o)
{
var p = o as Parent;
if (object.Equals(p, null))
return false;
return this.x == p.x;
}
public override int GetHashCode()
{
return x;
}
public static bool operator ==(Parent a, Parent b)
{
return a.Equals (b);
}
public static bool operator !=(Parent a, Parent b)
{
return !(a == b);
}
}
public class Child : Parent
{
public Child (int x)
: base(x)
{
}
}
public class Gen<T>
where T : Parent
{
public T variable;
public Gen (T x)
{
this.variable = x;
}
public override bool Equals(object o)
{
if (object.Equal(o, null)) return false;
// CAUTION: VERY DIRTY - just a quick reply to hvd - should check/remove this with test cases!
try
{
var oT = o.GetType ().GetGenericTypeDefinition ();
var tT = this.GetType ().GetGenericTypeDefinition ();
if (tT != oT)
return false;
// for example this:
// var oVar = o.GetType().GetField ("variable").GetValue (o);
// should really be
var varField = o.GetType().GetField("variable");
if (varField == null) return;
var oVar = varField.GetValue(o);
if (object.Equals(oVar, null))
return object.Equals(this.variable, null);
return this.variable.Equals (oVar);
} catch { return false; }
}
public override int GetHashCode()
{
return variable.GetHashCode();
}
public static bool operator ==(Gen<T> a, object b)
{
return a.Equals (b);
}
public static bool operator !=(Gen<T> a, object b)
{
return !(a == b);
}
}
Here is yours and another example: 这是你的另一个例子:
public static void Test()
{
Gen<Parent> foo = new Gen<Parent>(new Parent(5));
Gen<Child> bar = new Gen<Child>(new Child(5));
Gen<Child> bas = new Gen<Child>(new Child(6));
if (foo == bar)
Console.WriteLine ("equal");
else
Console.WriteLine ("not-equal");
if (foo == bas)
Console.WriteLine ("equal");
else
Console.WriteLine ("not-equal");
}
btw: you don't really need the (==) and (!=) on the Parent
class - but well it does not hurt 顺便说一下:你真的不需要Parent
类的(==)和(!=) - 但它不会伤害它
(expanding from the comments) A generic class doesn't seem to be necessary. (从评论中扩展)通用类似乎没有必要。 A valid approach for getting operators to work for generic types is to re-work the types so that they're no longer generic. 让运算符为泛型类型工作的有效方法是重新处理类型,使它们不再是通用的。
ColorSet
could be defined as ColorSet
可以定义为
public class ColorSet {
private Color red;
private Color green;
private Color blue;
protected ColorSet(Type type) {
red = (Color)Activator.CreateType(type);
red.Name = Values.Res.get("red");
green = (Color)Activator.CreateType(type);
green.Name = Values.Res.get("red");
blue = (Color)Activator.CreateType(type);
blue.Name = Values.Res.get("red");
}
public static ColorSet FromType<T>() where T : Color {
return new ColorSet(typeof(T));
}
}
Instead of new ColorSet<ExtendedColor>()
, you would now call ColorSet.FromType<ExtendedColor>()
. 现在,您将调用ColorSet.FromType<ExtendedColor>()
而不是new ColorSet<ExtendedColor>()
ColorSet.FromType<ExtendedColor>()
。
This works so long as you don't actually need to use your T
outside of your constructor. 只要您不需要在构造函数之外使用T
,这就可以工作。
If you had, for instance, a 例如,如果你有一个
public T Red { get { return red; } }
property, you would need to change that to a 属性,你需要将其更改为
public Color Red { get { return red; } }
property. 属性。
However, if you have anything like that, and you do want to keep the generic type, you can then put that in a derived generic class: 但是,如果您有类似的内容,并且确实希望保留泛型类型,则可以将其放在派生的泛型类中:
public class ColorSet<T> : ColorSet where T : Color {
public ColorSet<T>() : base(typeof(T)) { }
public new T Red { get { return (T)base.Red; } }
}
which still only needs operators for the base non-generic ColorSet
class. 它仍然只需要基础非泛型ColorSet
类的运算符。
public class IGen<out T>
where T : Parent
{
T Variable{ get; }
}
public class Gen<T>
: IGen<T>
where T : Parent
{
public T Variable {get;set;}
private static Func<T, T, bool> _equal;
static Gen()
{
var left = Expression.Parameter(typeof(T));
var right = Expression.Parameter(typeof(T));
var body = Expression.Equal(left, right);
var lambda = Expression.Lambda<Func<T, T, bool>>(body, left, right);
_equal = lambda.Compile();
}
public static bool operator ==(Gen<T> left, Gen<T> right)
{
return _equal(left.Variable, right.Variable);
}
public static bool operator ==(Gen<T> left, IGen<T> right)
{
return _equal(left.Variable, right.Variable);
}
public static bool operator ==(IGen<T> left, Gen<T> right)
{
return _equal(left.Variable, right.Variable);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.