我有一个用C#编写的项目。我试图将一个对象转换为一个接受枚举对象作为泛型参数的类。
我有以下课程
public class GenericEnumViewModel<TEnum> where TEnum : struct
{
[Required]
public TEnum? Value { get; set; }
public IEnumerable<SelectListItem> Options { get; set; }
}
这是我的一个枚举对象的示例
public enum TestEnum
{
First,
Second,
Third,
Fourth
}
最后,我有一个像这样的object
类型的变量
object obj = new GenericEnumViewModel<TestEnum>(); // Notice at this point I don't know that the generic type is `TestEnum` it could be any Enum.
如何检查变量obj
是否实现了GenericEnumViewModel<Enum>
?另外,我如何将一个名为castedObj
的新变量作为GenericEnumViewModel<Enum>
我正在尝试访问castedObj.Value
和castedObj.Options
。
我希望能够做这样的事情
var castedObj = obj as GenericEnumViewModel<Enum>;
if(castedObj != null)
{
// do something with castedObj.Value and castedObj.Options.
}
如何检查变量obj是否实现了GenericEnumViewModel?
您可以使用反射执行此操作:
object obj = new GenericEnumViewModel<TestEnum>();
var objType = obj?.GetType();
var enumType =
objType != null && objType.IsGenericType && objType.GetGenericTypeDefinition() == typeof(GenericEnumViewModel<>) ?
objType.GetGenericArguments()[0] :
throw new InvalidOperationException($"Object is not a closed type of {typeof(GenericEnumViewModel<>).FullName}");
另外,我如何将一个名为castedObj的新变量作为GenericEnumViewModel
由于多种原因,这是不可能的。以下行不会编译:
// this code is invalid!
GenericEnumViewModel<Enum> model = new GenericEnumViewModel<TestEnum>();
首先,covariance仅允许C#中的接口,数组和委托。
此外,即使类允许协方差,System.Enum也是引用类型,而枚举是值类型。将枚举值分配给System.Enum变量涉及boxing。这本身就会使上述任务变得不可能。
但是,您可以通过非泛型接口(或抽象基类)的帮助解决此问题,如下所示:
public interface IGenericEnumViewModel
{
Enum Value { get; }
GenericEnumViewModel<SelectListItem> Options { get; }
}
public class GenericEnumViewModel<TEnum> : IGenericEnumViewModel where TEnum : struct
{
[Required]
public TEnum? Value { get; set; }
public GenericEnumViewModel<SelectListItem> Options { get; set; }
Enum IGenericEnumViewModel.Value => Value.HasValue ? Value.Value : (Enum)null;
}
// ...
if (obj is IGenericEnumViewModel castedObj)
{
// do something with castedObj.Value and castedObj.Options.
Enum value = castedObj.Value;
// ...
}
奖金
截至C#7.3 you can use Enum in generic type constraints!
public class GenericEnumViewModel<TEnum> : IGenericEnumViewModel where TEnum : struct, Enum
{
// ...
}
你做不了。 GenericEnumViewModel<TEnum>
它是open constructed type因为它没有完全指定泛型参数的类型。 CLR不允许构造任何open类型的实例,也不能在泛型类型代码本身之外使用open类型声明变量。你可以在GenericEnumViewModel<TEnum>
类中这样做:
GenericEnumViewModel<TEnum> viewModel;
但你不能在GenericEnumViewModel<TEnum>
课外做。毕竟TEnum
关键字在GenericEnumViewModel<TEnum>
之外不存在。
所以,你不能在GenericEnumViewModel<TEnum>
之外这样做
var castedObj = obj as GenericEnumViewModel<Enum>;
因为它是一样的
GenericEnumViewModel<TEnum> viewModel = obj as GenericEnumViewModel<Enum>;
当您使用var
时,编译器应推断变量类型并使用推断类型创建变量。但它无法使用GenericEnumViewModel<TEnum>
类型创建变量,因为它是开放类型,因为TEnum
在此上下文中不存在。
您可以添加新接口并明确实现它。然后,您可以使用C#7.0中引入的模式匹配。
public interface IGenericEnumViewModel
{
object Value { get; set; }
GenericEnumViewModel<SelectListItem> Options { get; set; }
}
public class GenericEnumViewModel<TEnum> : IGenericEnumViewModel where TEnum : struct
{
public TEnum? Value { get; set; }
public GenericEnumViewModel<SelectListItem> Options { get; set; }
object IGenericEnumViewModel.Value {
get {return Value;}
set {Value = (TEnum?)value;}
}
然后:
if(obj is IGenericEnumViewModel c)
{
//c is IGenericEnumViewModel
}