我有一个用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.
}
答案 0 :(得分:1)
如何检查变量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
{
// ...
}
答案 1 :(得分:0)
您不能这样做。 GenericEnumViewModel<TEnum>
是open constructed type,因为它没有确切指定泛型参数的类型。 CLR不允许构造任何开放类型的实例,并且您不能在通用类型代码本身之外使用开放类型声明变量。您可以在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
在这种情况下不存在。
答案 2 :(得分:-1)
您可以添加新接口并明确实现它。然后,您可以使用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
}