在声明超类时无法访问子类的通用属性

时间:2015-02-07 03:09:08

标签: c# generics polymorphism

我可能目前感到困惑,但我有以下问题。 我正在使用C#,但重点更为通用,但我是来自Java的C#的新手。

我有一个共同的抽象超类和多个孩子。 有些孩子有通用属性,当我在声明公共超类型时实例化变量时,我无法访问这些属性:

abstract class A
{
    public string Prop0;
}

// Here every ok when instantiated
class B: A
{
    public string Prop1;
}

// This makes trouble
class C<T> : A
{
    public T Prop2;
}

现在我有一个返回A:

的子类型的方法
public A DoIt()
{
    A a;
    a = new C<string>();
    a.Prop2; // <-- Can't access
}

(在我的具体情况下,类型不能是静态的,因为子类是序列化的并且具有不同的形状(C是具有允许任何内容的属性的模板)。仍然是一般的问题)

为什么这是一个问题,哪个解决方案是“正确的”(除了使用“对象”)

2 个答案:

答案 0 :(得分:3)

如果始终将a设置为C的新实例,则只需将其声明为:

public A DoIt()
{
    C<string> c;
    c = new C<string>();
    var prop2 = c.Prop2;
    return c;
}

但是,如果你不知道它是否是C,直到它被反序列化 - 这听起来就是你的解释就是这里的情况 - 那么这是一种获得该属性的方法,如果事实上它是C(如果不是null,则获取C):

public A DoIt()
{
    A a;
    a = new C<string>();
    var prop2 = a is C<string> ? (a as C<string>).Prop2 : null;
    return a;
}

基本上,第二种方法的作用是检查aC的实例,如果是,则将a转换为C,然后读取Prop2财产。

后续示例:

这是来自实际工作控制台应用程序的代码,它与您所描述的内容类似。这不是一个现实的场景,它可能与您的想法不太接近,但无论如何我会发布它,以防它给你任何想法。

请注意,这需要引用Json.NET(对于下面的using Newtonsoft.Json;声明)。

using System;
using Newtonsoft.Json;

...

static void Main(string[] args)
{
    var c = new C<string>() { Prop0 = "zero", Prop2 = "two" };
    var json = JsonConvert.SerializeObject(c);
    var prop2 = GetProp2(json);
    Console.WriteLine("prop2 from C: " + (prop2 ?? "null"));

    var b = new B() { Prop0 = "zero", Prop1 = "one" };
    json = JsonConvert.SerializeObject(b);
    prop2 = GetProp2(json);
    Console.WriteLine("prop2 from B: " + (prop2 ?? "null"));

    Console.Write("Press any key to exit...");
    Console.ReadKey();
}

static object GetProp2(string json)
{
    A a = JsonConvert.DeserializeObject<C<string>>(json);
    var prop2 = a is C<string> ? (a as C<string>).Prop2 : null;
    return prop2;
}

结果如下:

prop2 from C: two
prop2 from B: null
Press any key to exit...

答案 1 :(得分:1)

评论中问题的可能答案:“您如何声明Shape的某些子类型将被返回/实例化。”

如果您想要专门返回C<T>结果,可以将其指定为返回类型:

public C<TResult> DoIt<TResult>()
{
    C<TResult> a;
    a = new C<TResult>();
    a.Prop2; // <-- Can access
    return a;
}