3

我想要完成的是有两个类,一个非泛型和一个泛型。

我需要一个非泛型类,因为我打算插入这个类的对象并将它们插入到List<T>

这是代码

// Non-generic
public class Response
{
    public object Value { get; }
}

// Generic
public class Response<T> : Response
{
    public T Value { get; set; }
}

我想要一个List<Response>,当我访问这个对象时,我将 Value 属性作为对象。

但是当我收到这个对象作为通用对象时,访问 T Value 属性并隐藏对象 Value 属性。

我希望清楚,如果没有..请告诉我。

编辑:这是一个测验。因此,每个问题都有答案。例如,在 MultipleChoiceQuestion 中,它可以有多个答案 A、B、C、D 作为视图形状,或者可以是字符串或整数。

public abstract class Question
{
    public Question(string questionText)
    {
        this.QuestionText = questionText;
    }

    public string QuestionText { get; set; }
}

// Non-generic
public class Response
{
    public object Value { get; }
}

// Generic
public class Response<T> : Response
{
    public T Value { get; set; }
}

public class MathProblemQuestion : Question
{
    public Response Response { get; set; }
}

public class MultipleChoiseQuestion : Question
{
    public Response Response { get; set; }

    public IEnumerable<Response> PossibleResponses;

    ...
}

public class TrueOrFalse : Question
{
    ...
}
4

6 回答 6

10

我个人只会给他们不同的名字。它会让你的生活简单,代码也更清晰:

public abstract class Response
{
    public abstract object ObjectValue { get; }
}

public class Response<T> : Response
{
    public T Value { get; set; }

    public override object ObjectValue { get { return Value; } }
}

请注意,我已经将Response类抽象化了——很难看出它如何优雅地工作;如果Response有自己的存储空间,Value那么大概可以将其设置为非T值。希望制作这份摘要对您来说不是问题。

于 2012-06-29T17:49:39.157 回答
2

我需要一个非泛型类,因为我打算插入这个类的对象并将它们插入到List<T>

不确定我是否理解。AList<T>当然可以保存泛型类型。

var ls = new List<List<int>>;  // works!

如果您退回到object到处使用,那么使用泛型有什么意义呢?您不再拥有用于所有意图和目的的强类型集合,因为底层数据(您真正关心的数据)属于object.

但是当我收到这个对象作为通用对象时,访问 T Value 属性并隐藏对象 Value 属性。

如果您使用Response<object>thenT object适用于您类型的所有实例。

也许我在这里遗漏了一些东西。如果我是,你能详细说明一下吗?我看不出您的泛型类型不起作用的原因。

编辑:我想我现在明白了。您想要一个单独的对象List<T>来保存Response具有不同通用参数的对象。如果可能的话,我建议限制每种泛型类型以实现特定的接口,即

public interface IResponseData
{
    // whatever
}

public class Response<T> where T : IResponseData
{
    public T Value { get; set; }
}

现在,如果您需要允许ints 和其他没有共同祖先的类型,那么这将不起作用,Jon Skeet 为您提供了更好的解决方案。

于 2012-06-29T17:49:48.943 回答
1

为了做你想做的事,你需要把这两个值联系在一起:

public abstract class Response
{
    public object Value { get; set; }
}

public class Response<T> : Response
{
    private T _value;
    public new T Value
    {
        get { return _value; }
        set { base.Value = _value = value; }
    }
}

但是,正如其他人指出的那样 - 您的前提是不正确的:您可以将泛型类型用作其他泛型类型中的类型参数:

List<Response<YourObject>> 

将是完全有效的。

于 2012-06-29T18:16:55.473 回答
0

如果您执行以下操作(使用“new”关键字),您将隐藏基类上的属性:

// Non-generic
public class Foo
{
    public object Value { get; set; }
}

// Generic
public class Foo<T> : Foo
{
    public new T Value { get; set; }
}

除非您添加另一个名称不同的属性,否则我看不到解决方法。我不完全理解为什么你需要使用不同版本的类才能使用一个列表,你可以有一个 List< Foo < T > > 就好了。

于 2012-06-29T17:51:51.430 回答
0

我假设您希望在同一个列表中插入不同类型的响应,并使响应的对象版本不可设置。但是下面的代码不起作用,因为属性的自动生成的后备存储没有绑定在一起:

// Non-generic
public class Response
{
    public object Value { get; private set; }
}
// Generic
public class Response<T> : Response
{
    public new T Value { get; set; }
}

public static void Main()
{
    List<Response> List = new List<Response>() { new Response<int>() { Value = 1 }, new Response<string>() { Value = "p" } };

    // Throws NullReferenceException
    Console.WriteLine(list[0].Value);
    Console.WriteLine(list[1].Value);
}

试试这个,它使用受保护的字段来支持属性:

// Non-generic
public class Response
{
    protected object valueObject;

    public object Value
    {
        get
        {
            return valueObject;
        }
    }
}
// Generic
public class Response<T> : Response
{
    public new T Value
    {
        get
        {
            return (T)valueObject;
        }
        set
        {
            valueObject = value;
        }
    }
}

public static void RunSnippet()
{
    List<Response> list = new List<Response>() { new Response<int>() { Value = 1 }, new Response<string>() { Value = "p" } };

    Console.WriteLine(list[0].Value);
    Console.WriteLine(list[1].Value);
}
于 2012-06-29T18:01:06.420 回答
0

如果我正确理解您的问题,您可以做您想做的事,只要您愿意在读回列表元素时手动对它们进行类型转换。

您问题的第一部分是,您如何用不同类型的新属性“隐藏”继承的属性,而您已经实现了这一点。您不需要任何特殊关键字来替换属性。给定您的样本类型:

public class Response
{
    public object Value
    {
        get;
        set;
    }
}

public class Response<T> : Response
{
    public T Value
    {
        get;
        set;
    }

}

您已经可以执行以下操作:

// typeof(response.Value) == System.Object
var response = new Response();

// typeof(responseint.Value) == System.Int32
var responseint = new Response<int>();

但是,您进一步要求做的是将它们放入 aList<Response>并仍将它们视为派生类型,如果没有显式类型转换,将无法工作。a 的元素类型List<>在编译时是固定的,据编译器所知,列表的所有元素都具有该类型。如果需要,您可以将更多派生类型添加到列表中,但是一旦它们在那里,当您退出时,编译器只知道它们是基类型。

当然,在运行时,实际的类型元数据是存在的,所以运行时知道如何将 aResponse转换为 a Response<int> ,只要它是真实的。为了在代码中进行演示,给定上述Response和的实例Response<int>

 // this part is fine, but...
var responses = new List<Response>();
responses.Add(response);
responses.Add(responseint); 

// This will not work.
responses[1].Value += 1; 

// But this will.
(responses[1] as Response<int>).Value += 1;
于 2012-06-29T18:01:30.143 回答