如何在 C# 中将具有 `object` 类型的变量转换为具有泛型类型的 class?

How can I cast a variable with the `object` type to class with generic type in c#?

我有一个用 C# 编写的项目。我正在尝试将一个对象转换为接受枚举对象作为通用参数的 class。

我有以下class

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.ValuecastedObj.Options

我希望能够做这样的事情

var castedObj = obj as GenericEnumViewModel<Enum>;

if(castedObj != null)
{
      // do something with castedObj.Value and castedObj.Options.
}

您可以添加新接口并显式实现它。然后你可以使用 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 
}

How can I check if the variable obj implements 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}");

Also how can I make a new variable called castedObj as GenericEnumViewModel

由于多种原因,这是不可能的。以下行将无法编译:

// this code is invalid!
GenericEnumViewModel<Enum> model = new GenericEnumViewModel<TestEnum>();

首先,covariance 只允许在 C# 中用于接口、数组和委托。

此外,即使 classes 允许协方差,System.Enum is a reference type while enums are value types. Assigning an enum value to a System.Enum variable involves boxing。这本身会使上述任务变得不可能。

但是,您可以借助非通用接口(或抽象基 class)解决此问题,如下所示:

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
{
    // ...
}