[英]Using a generic type passed without constraint with a constrained generic type
Lets say we have the following classes:假设我们有以下类:
public interface IFrobnicator<T> { }
class ComparableFrobnicator<T> : IFrobnicator<T> where T : IComparable<T>
{
public ComparableFrobnicator(T value) { }
}
class EquatableFrobnicator<T> : IFrobnicator<T> where T : IEquatable<T>
{
public EquatableFrobnicator(T value) { }
}
You can write methods你可以写方法
public IFrobnicator<T> MakeFrobnicatorFromComparable<T>(T value) where T : IComparable<T>
{
return new ComparableFrobnicator<T>(value);
}
public IFrobnicator<T> MakeFrobnicatorFromEquatable<T>(T value) where T : IEquatable<T>
{
return new EquatableFrobnicator<T>(value);
}
If I wanted to unify that into a single method, the most obvious way won't compile:如果我想将其统一为一个方法,最明显的方法将无法编译:
public IFrobnicator<T> MakeFrobnicator<T>(T value)
{
if (value is IComparable<T>)
{
return new ComparableFrobnicator<T>(value);
}
else if (value is IEquatable<T>)
{
return new EquatableFrobnicator<T>(value);
}
else throw new ArgumentException();
}
That raises the following error when compiled:编译时会引发以下错误:
CS0314 The type 'T' cannot be used as type parameter 'T' in the generic type or method 'UserQuery.ComparableFrobnicator'.
CS0314 类型“T”不能用作泛型类型或方法“UserQuery.ComparableFrobnicator”中的类型参数“T”。 There is no boxing conversion or type parameter conversion from 'T' to 'System.IComparable'.
没有从“T”到“System.IComparable”的装箱转换或类型参数转换。
I can't replace new ComparableFrobnicator <T>
with new ComparableFrobnicator<IComparable<T>>
because that causes problems down the line with getting value
back out - you cannot cast from an interface type to a concrete type.我不能用
new ComparableFrobnicator<IComparable<T>>
替换new ComparableFrobnicator <T>
,因为这会导致取回value
问题 - 您不能从接口类型转换为具体类型。
So instead, I went the route of reflection:所以相反,我走的是反思路线:
public IFrobnicator<T> MakeFrobnicator<T>(T value)
{
if (value is IComparable<T>)
{
var constructor = typeof(ComparableFrobnicator<>).MakeGenericType(typeof(T)).GetConstructor(new[] { typeof(T) });
return (IFrobnicator<T>)constructor.Invoke(new object[] { value});
}
else if (value is IEquatable<T>)
{
var constructor = typeof(EquatableFrobnicator<>).MakeGenericType(typeof(T)).GetConstructor(new[] { typeof(T) });
return (IFrobnicator<T>)constructor.Invoke(new object[] { value });
}
else throw new ArgumentException();
}
That seems to work perfectly, but looks like a step backwards in a language with such powerful type inference as I'm used to.这似乎工作得很好,但在我习惯的具有如此强大类型推断的语言中,这看起来像是倒退了一步。 Is there something I'm missing, or a better technique I missed?
是否有我遗漏的东西,或者我遗漏了更好的技术?
Try the extention methods approach, The way value.MakeFrobnicator() is implemented helps to resolve generic type params issue尝试扩展方法方法,实现value.MakeFrobnicator()的方式有助于解决泛型类型参数问题
public interface IFrobnicator<T> { }
public class ComparableFrobnicator<T> :IFrobnicator<T>
where T :IComparable<T>
{
public ComparableFrobnicator(T param) { }
}
public class EquatableFrobnicator<T> :IFrobnicator<T>
where T : IEquatable<T>
{
public EquatableFrobnicator(T value) { }
}
public static class FrobnicatorExtentions
{
public static IFrobnicator<T>
MakeFrobnicatorFromComparable<T>(this T value)
where T: IComparable<T>
{
//return new ComparableFrobnicator<T>(value);
return value.MakeFrobnicator();
}
public static IFrobnicator<T>
MakeFrobnicatorFromEquatable<T>(this T value)
where T : IEquatable<T>
{
// return new EquatableFrobnicator<T>(value);
return value.MakeFrobnicator();
}
public static IFrobnicator<T>
MakeFrobnicator<T>(this IEquatable<T> value)
where T: IEquatable<T>
{
if (value is T)
{
if (value is IEquatable<T>)
{
return new EquatableFrobnicator<T>((T)value);
}
}
throw new InvalidCastException();
}
public static IFrobnicator<T>
MakeFrobnicator<T>(this IComparable<T> value)
where T : IComparable<T>
{
if (value is T)
{
if (value is IComparable<T>)
{
return new ComparableFrobnicator<T>((T)value);
}
}
throw new InvalidCastException();
}
}
Have you tried doing a cast?你试过做演员吗?
public IFrobnicator<T> MakeFrobnicator<T>(T value)
{
if (value is IComparable<T>)
{
return new ComparableFrobnicator<T>((IComparable<T>)value);
}
else if (value is IEquatable<T>)
{
return new EquatableFrobnicator<T>((IEquatable<T>)value);
}
else throw new ArgumentException();
}
I can't remember off the top of my head if that's at all valid.如果这完全有效,我不记得我的头顶。 Either way, it's not very open/closed.
无论哪种方式,它都不是很开放/封闭。 You could instead write a list of converters that each decide if they are the appropriate type to do the conversion.
您可以编写一个转换器列表,每个转换器决定它们是否适合进行转换。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.