并感谢您的帮助。
如何从未知Generic.List类型的方法返回。
public void Main()
{
List<A> a= GetData("A");
}
public List<T> GetData(string listType)
{
if(listType == "A")
{
List<A> a= new List<A>()
...
return a;
}
else
{
List<B> b = new List<B>()
return b;
}
}
在下面的示例中,我收到类似于以下内容的错误:无法将List<A>
转换为List<T>
这可能吗?错误发生在'return a;'上代码行。
另外,我需要做些什么来确保线路上不会发生错误:
List<A> a= GetData("A");
谢谢, 史蒂文
答案 0 :(得分:23)
使用IList
代替List<T>
。
答案 1 :(得分:13)
仅限于返回对象列表的替代方法是确保A和B派生自公共基类型或实现公共接口,然后返回该基类型或接口的列表。在Generic方法中包含一个约束: -
List<ICommon> GetData<T>() where T: ICommon
{
}
答案 2 :(得分:9)
您无法直接返回此类List<T>
。
为什么呢?基本上因为List<A>
和List<B>
(或List<string>
vs List<int>
这是相同的事情)被视为2个完全独立的无关类。
正如您无法从声明返回string
的函数返回int
一样,您无法从声明返回整数列表的函数返回字符串列表。 <T>
这里有点红鲱鱼。你不能写一个返回字符串和整数的通用方法......
有关此类事情的详情,请参阅here。
所以你需要做的就是返回两种类型的东西(它们“有共同之处”。)
作为John Rasch says,您可以返回IList
,(请注意非通用,因此它只是object
s的列表)或只是将其作为object
返回。不幸的是,没有办法保留列表的类型。
答案 3 :(得分:7)
除非有特定原因导致您无法提前指定实际类型,否则您可以将方法本身设为通用:
public void Main() {
List<A> a = GetData<A>();
}
public List<TType> GetData<TType>() {
List<TType> list= new List<TType>();
...
return list;
}
答案 4 :(得分:5)
编辑每个猎户座的答案如下,加上AnthonyWJones暗示的禁令
你可能应该有一个接口/抽象类,A和B继承自
public interface IMyInterface { }
public class A : IMyInterface { }
public class B : IMyInterface { }
public List<IMyInterface> GetData<T>() where T : IMyInterface
{
List<IMyInterface> myList = new List<IMyInterface>();
if (typeof(T) == typeof(A))
{
myList.Add(new A());
}
if (typeof(T) == typeof(B))
{
myList.Add(new B());
}
return myList;
}
答案 5 :(得分:2)
最近我不得不解决类似的问题,所提议的解决方案都不令人满意;约束类型参数是不实际的。相反,我让方法的消费者决定如何挖掘数据。例如,您可以编写一个返回强类型List的String.Split()的泛型版本,只要您告诉它如何将子串转换为T。
一旦你愿意将责任转移到调用堆栈(并且可以轻松地传递lambda),你可以任意概括这个模式。例如,如果GetData()的方式不同(正如某些响应显然所假设的那样),您也可以将该函数提升到调用者的范围内。
演示:
static void Main(string[] args)
{
var parseMe = "Hello world! 1, 2, 3, DEADBEEF";
// Don't need to write a fully generic Process() method just to parse strings -- you could
// combine the Split & Convert into one method and eliminate 2/3 of the type parameters
List<string> sentences = parseMe.Split('!', str => str);
List<int> numbers = sentences[1].Split(',', str => Int32.Parse(str, NumberStyles.AllowHexSpecifier | NumberStyles.AllowLeadingWhite));
// Something a little more interesting
var lettersPerSentence = Process(sentences,
sList => from s in sList select s.ToCharArray(),
chars => chars.Count(c => Char.IsLetter(c)));
}
static List<T> Split<T>(this string str, char separator, Func<string, T> Convert)
{
return Process(str, s => s.Split(separator), Convert).ToList();
}
static IEnumerable<TOutput> Process<TInput, TData, TOutput>(TInput input, Func<TInput, IEnumerable<TData>> GetData, Func<TData, TOutput> Convert)
{
return from datum in GetData(input)
select Convert(datum);
}
函数式编程大师可能会对这种探索持怀疑态度:“你只是在编写Map几次。”即使是C ++人也可能会声称这是一个模板技术(即STL transform()+ functor)需要的工作量少于泛型的例子。但作为主要使用C#的人,很高兴找到一种既能保护类型安全又能保留惯用语言的解决方案。
答案 6 :(得分:2)
您可以执行以下操作:
public void Main()
{
List<int> a = GetData<int>();
List<string> b = GetData<string>();
}
public List<T> GetData<T>()
{
var type = typeof(T);
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
{
type = type.GenericTypeArguments[0];
}
if (type == typeof(int))
{
var a = new List<int> { 1, 2, 3 };
return a.Select(v => v != null ? (T)Convert.ChangeType(v, type) : default(T)).ToList();
}
else if (type == typeof(string))
{
var b = new List<string> { "a", "b", "c" };
return b.Select(v => v != null ? (T)Convert.ChangeType(v, type) : default(T)).ToList();
}
}
也许您可以根据需要进行修改。
答案 7 :(得分:1)
如果你在运行时之前不知道你想要的类型,那么泛型可能是错误的工具。
如果你的函数根据参数显着改变行为(比如改变返回类型),那么它应该是两个函数。
看起来这个函数不应该是通用的,实际上应该是两个函数。
public void Main() {
List<A> a = GetDataA();
}
public List<A> GetDataA() {
List<A> a= new List<A>()
...
return a;
}
public List<B> GetDataB() {
List<B> b= new List<B>()
...
return b;
}
答案 8 :(得分:0)
我知道它的方式为时已晚,但我带着同样的问题来到这里,这就是我使用接口的方法。以为我会发布它以造福他人
public interface IEntity
{
int ID
{
get;
set;
}
}
public class Entity2:IEntity
{
public string Property2;
public int ID
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
}
与Entity1类似。
现在我的班级(我的业务层)我有这个方法
public List<IEntity> GetEntities(Common.EntityType entityType)
{
List<IEntity> entities = new List<IEntity>();
switch (entityType)
{
case Common.EntityType.Accounts:
Entity1 entity1 = new Entity1();
entity1.Property1 = "AA";
entities.Add(entity1);
break;
case Common.EntityType.Brands:
Entity2 entity2 = new Entity2();
entity2.Property2 = "AA";
entities.Add(entity2);
break;
default:
break;
}
return entities;
}
在UI中,我会这样称呼它
BusinessClass b = new BusinessClass();
List<IEntity> a = b.GetEntities(Common.EntityType.Accounts);
希望这有帮助