我正在努力实现的是两个类,非泛型和通用。
我需要一个非泛型类,因为我打算插入此类的对象并将它们插入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
{
...
}
答案 0 :(得分: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
值。希望这个摘要对你来说不是问题。
答案 1 :(得分:2)
我需要一个非泛型类,因为我打算插入此类的对象并将它们插入
List<T>
不确定我明白这一点。 List<T>
当然可以包含泛型类型。
var ls = new List<List<int>>; // works!
如果你再回到使用object
,那么使用泛型有什么意义呢?您不再拥有强类型集合用于所有意图和目的,因为基础数据(您真正关心的数据)属于object
类型。
但是当我将此对象作为泛型接收时,访问T Value属性并隐藏对象Value属性。
如果您使用Response<object>
,那么T
object
适用于您所有类型的实例。
也许我在这里遗漏了一些东西。如果我能为你详细说明吗?我认为你的通用类型没有理由不起作用。
编辑:我想我现在明白了。您希望单个List<T>
保存具有不同通用参数的Response
个对象。如果可能,我建议限制每个泛型类型以实现特定的接口,即
public interface IResponseData
{
// whatever
}
public class Response<T> where T : IResponseData
{
public T Value { get; set; }
}
现在,如果您需要允许int
和其他没有共同祖先的类型,那么这将无效,Jon Skeet为您提供了更好的解决方案。
答案 2 :(得分: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>>
完全有效。
答案 3 :(得分: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&lt; Foo&lt; T> &GT;很好。
答案 4 :(得分:0)
我假设您要在同一列表中插入不同类型的响应,并使Response的对象版本不可设置。但是,下面的代码不起作用,因为属性的自动生成的后备存储不是捆绑在一起的:
// 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);
}
答案 5 :(得分: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>();
然而,你要进一步要求做的是,将它们放入List<Response>
并仍将它们视为派生类型,如果没有明确的类型转换,将无法工作。 List<>
的元素类型在编译时是固定的,并且就编译器所知,列表的所有元素都具有该类型。如果需要,可以向列表中添加更多派生类型,但是一旦它们在那里,当你得到退出时,编译器只知道它们是基类型。
在运行时,当然,存在实际的类型元数据,因此运行时知道如何将Response
转换为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;