【问题标题】:Getting a value from a generic method without supplying the type从泛型方法获取值而不提供类型
【发布时间】:2015-10-21 18:20:47
【问题描述】:

我试图创建一个类,其中一个属性是通用的,而类本身是通用的。我发现你不能那样做;不允许使用通用属性。我也在这里挖掘了一下线程Making a generic property,如果我找到了适合我的解决方法。

后来,我就上了这门课……

[Serializable]
public class ConfigurationItem
{
    private readonly Type type;

    public string Description { get; set; }

    public IDictionary<string, ConfigurationItem> Items { get; private set; }

    public string Name { get; set; }

    public string Summary { get; set; }

    public object Value { get; private set; }

    public ConfigurationItem(string name, Type type = null, object value = null)
    {
        this.Name = name;
        this.type = type ?? typeof(string);
        this.Value = value;
        Items = new Dictionary<string, ConfigurationItem>();
    }

    public string Export()
    {
        return JsonConvert.SerializeObject(this);
    }

    public T GetValue<T>()
    {
        return (T)Convert.ChangeType(Value, type);
    }
}

现在我唯一的问题是,如果我想获得正确转换的值,我必须在调用GetValue() 时提供类型。本能地,我不禁觉得,鉴于该类知道应该返回的类型,我应该可以构造一个不需要我提供任何其他信息的GetValue() 方法。

我不知道怎么做。

我确实找到了线程 Getting a generic method to infer the type parameter from the runtime type,这似乎表明这是可能的,但我对反射知之甚少,无法理解所说的内容。

有没有一种方法可以构造一个不需要我提供泛型类型的GetType() 方法?你能用我微弱的大脑能理解的方式解释吗?

编辑 许多人实际上已经指出,无论如何我真的不需要这样做,但作为一个学习练习,我遵循了@ShoaibShakeel 的建议来查看 C# dynamic 类型并想出了这些额外的方法。 ..

    public dynamic GetValue()
    {
        return typeof(ConfigurationItem)
            .GetMethod("GetReturnValue", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)
            .MakeGenericMethod(type)
            .Invoke(this, new object[] { });
    }

    private T GetReturnValue<T>()
    {
        return (T)Convert.ChangeType(Value, type);
    }

【问题讨论】:

  • 如果不指定类型,CLR 将无法知道要从内存中读取多少数据以及如何解析它。我认为你应该看看 dynamic type 。 msdn.microsoft.com/en-us/library/dd264736.aspx
  • 为什么不只是object?在这里注入运行时评估类型没有意义。毕竟,返回类型只能帮助您进行编译时类型检查。在这种情况下,这显然是不可能的。所以object 很好。或者,如果调用者知道类型,那么您的泛型方法可能更可取。
  • @NicoSchertler 我明白你的意思,我想我在这方面没有考虑。但是,请参阅我的编辑。
  • 为什么不只是return Value;?无需调用泛型函数。

标签: c# generics


【解决方案1】:

本能地,我不禁感到,因为类知道应该返回的类型

虽然Value 对象确实知道自己的类型,但此信息仅在运行时可用(一旦存在具有类型的实际对象)。因此,为了在编译时获得类型信息,您需要提供必要的信息。毕竟,不可能静态地知道那里分配了什么对象。

但是假设 GetValue() 能够自动返回 typed 对象,你想用它做什么?

var x = configurationItem.GetValue();

那么x 应该是什么类型,之后你想用它做什么?你只想打印它还是什么?那么object 就足够了。你想用它计算一些东西吗?那么您已经要求它是 intfloat 或其他东西,因此您需要一个实际的静态类型——这就是您必须提供该类型信息的原因。

仅仅因为返回类型是object,并不意味着对象本身就丢失了类型信息。分配给 object 属性的字符串仍将是字符串,即使您稍后检索它也是如此。如果你期望一个字符串并且想用它做一些事情,那么你当然可以将它转换为一个字符串。

【讨论】:

  • 你说得对,我只是不喜欢一直写出泛型类型的想法(我天生懒惰)。但是,请参阅我的编辑。
  • @StuartHemming 问题仍然存在:你为什么要在那里有一个静态类型?如果您不想在之后对对象执行任何特定于类型的操作,则无需拥有它。 dynamic 解决方案也没有给您带来任何好处,因为您 1) 可以直接将 Value 返回为 dynamic,并且 2) 因为 dynamic 为您提供与 object 一样多的类型信息。
  • 我想我忽略了一个事实,即我确实希望(至少可能)能够在获得该值时使用该值执行特定于类型的事情背部。我没有想到将 Value 属性返回为dynamic,因为我真的不知道。遵循这一点得出我得出的结论的唯一要点是通过对我的学习练习和对像我这样在未来面临类似问题的任何人的教学练习。
【解决方案2】:

没有。

编译器无法从分配给它的变量推断类型,因为它是模棱两可的,尤其是在大型继承树中。

考虑线

object o = configurationItem.GetValue<int>();

int 可能是您价值的有效转换,但object 不是,因为object 没有实现IConvertible 接口(@98​​7654326@ 需要。

【讨论】:

    【解决方案3】:

    我能够让我的类返回一个值,正确转换,使用反射和动态,使用以下添加到我的原始类。

    public dynamic GetValue()
    {
        return typeof(ConfigurationItem)
            .GetMethod("GetReturnValue", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)
            .MakeGenericMethod(type)
            .Invoke(this, new object[] { });
    }
    
    private T GetReturnValue<T>()
    {
        return (T)Convert.ChangeType(Value, type);
    }
    

    【讨论】:

      猜你喜欢
      • 2013-04-17
      • 1970-01-01
      • 2011-05-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多