【问题标题】:Use Generic Type and Interface in building a List with C#在使用 C# 构建列表时使用泛型类型和接口
【发布时间】:2016-05-25 15:50:44
【问题描述】:

我有以下界面:

public interface IModel
{
    string Code { get; set; }
    string Description { get; set; }
}

我有十几个类实现,示例:

public interface Obj1 : IObj1
{
    string Code { get; set; }
    string Description { get; set; }
}

public interface Obj2 : IObj2
{
    string Code { get; set; }
    string Description { get; set; }
}

IObj1 和 IObj2 都实现了 IModel:

public interface IObj1 : IModel {}
public interface IObj2 : IModel {} 

在我的单元测试中,我为每个对象创建了带有值的模拟列表。目前我的代码如下所示:

public static List<IObj1> Obj1ListCacheMock()
{
    var list = new List<IObj1>();

    list.Add(new Obj1() { Code = "S1", Description = "Test 1" });
    list.Add(new Obj1() { Code = "S2", Description = "Test 2" });
    list.Add(new Obj1() { Code = "S3", Description = "Test 3" });

    return list;
}

public static List<IObj2> Obj2ListCacheMock()
{
    var list = new List<IObj1>();

    list.Add(new Obj2() { Code = "S1", Description = "Test 1" });
    list.Add(new Obj2() { Code = "S2", Description = "Test 2" });
    list.Add(new Obj2() { Code = "S3", Description = "Test 3" });

    return list;
}

我的目标是只有一种方法可以返回测试对象列表。比如:

public static List<IModel> Obj2ListCacheMock<IModel>()
{
    var list = new List<IModel>();

    list.Add(new { Code = "S1", Description = "Test 1" });
    list.Add(new { Code = "S2", Description = "Test 2" });
    list.Add(new { Code = "S2", Description = "Test 3" });

    return list;
}

此代码错误:

错误 CS1503 参数 1:无法从 '' 转换为 'IModel'

我该如何完成这项工作,或者是否有更好的方法来实现我的目标?

【问题讨论】:

  • “不起作用”是什么意思?
  • @GendoIkari,我用错误更新了问题。

标签: c# .net generics interface


【解决方案1】:

您可以为parameterless constructor 创建一个带有约束的泛型方法:

public static List<T> GetListCacheMock<T>() where T : IModel, new()
{
    var list = new List<T>();

    list.Add(new T { Code = "S1", Description = "Test 1" });
    list.Add(new T { Code = "S2", Description = "Test 2" });
    list.Add(new T { Code = "S2", Description = "Test 3" });

    return list;
}

然后,像这样使用它:

List<Obj1> obj1s = GetListCacheMock<Obj1>(); //Assuming Obj1 is class  with a parameterless constructor
List<Obj2> obj2s = GetListCacheMock<Obj2>(); //Same for Obj2

如果您的类没有无参数构造函数,您可以传递 Func&lt;T&gt; 来创建类型实例:

public static List<T> GetListCacheMock<T>(Func<T> getNew) where T : IModel
{
    var list = new List<T>();

    var item1 = getNew();
    item1.Code = "S1";
    item1.Description = "Test 1";

    list.Add(item1);
    ...

    return list;
}

终于

List<Obj1> obj1s = GetListCacheMock<Obj1>(() => new Obj1(...));

【讨论】:

  • 完美。我尝试了一个约束,但没有第二个参数“new()”——它是如何工作的?
  • @Josh: new() 确保T 将有一个公共的无参数构造函数。这允许您创建 T 的实例。
  • 我遇到的唯一问题是我需要返回值是接口列表,而不是对象。因此,它需要是一个 List,而不是 List。如果这是您认为可以解决的问题,我可以将其作为新问题发布。
  • 我想通了,只是传递给参数(类和接口): public static List GetListCacheMock() where T : IModel, T2, new()
【解决方案2】:

您仍然必须指定要创建的对象。 这里:

new { Code = "S1", Description = "Test 1" }

您正在创建一个未实现 IModel 接口的匿名类型。

如果添加对象名称,它应该可以工作。

public static List<IModel> Obj2ListCacheMock<IModel>()
{
    var list = new List<IModel>();

    list.Add(new Obj1() { Code = "S1", Description = "Test 1" });
    list.Add(new Obj2() { Code = "S2", Description = "Test 2" });
    list.Add(new Obj1() { Code = "S2", Description = "Test 3" });

    return list;
}

【讨论】:

  • 我想使用传递的 IModel 类型,这样我就可以对不同的对象使用相同的函数。
  • @Josh:你想怎么过关?
  • @Josh 然后只需创建一个工厂方法,该方法根据“IModel”的类型以及创建它所需的任何其他参数来构建相应的对象。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多