如何将带有`object`类型的变量转换为带有c#泛型类的类?

问题描述 投票:3回答:3

我有一个用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.ValuecastedObj.Options

我希望能够做这样的事情

var castedObj = obj as GenericEnumViewModel<Enum>;

if(castedObj != null)
{
      // do something with castedObj.Value and castedObj.Options.
}
c# generics casting clr
3个回答
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
{
    // ...
}

0
投票

你做不了。 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在此上下文中不存在。


-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 
}
© www.soinside.com 2019 - 2024. All rights reserved.