【问题标题】:Why do I get NullReferenceException in my factory pattern implementation, c#?为什么我的工厂模式实现中会出现 NullReferenceException,c#?
【发布时间】:2017-12-28 17:07:46
【问题描述】:

主类:

public class ClP_Login
{
    private Form vrcView;
    private I_Repository<I_Identifiable> vrcRepository = null;

    public ClP_Login(Form vrpView)
    {
        vrcView = vrpView;
        SetTheme();
    }

    private void SetTheme()
    {
        if(vrcView !=null)
        vrcView.BackColor = Cl_BaseColor.StandardBackground;
    }

    public void CreateNewUser()
    {
        ClE_User test = new ClE_User();
        test.Name = "test name";
        test.Password = "";
        Cl_RepositoryFactory vrlFactory = new Cl_RepositoryFactory();
        vrcRepository = vrlFactory.CreateRepository(E_Repositories.User);
        vrcRepository.Add(test);
    }
}

Cl_RepositoryFactory 类:

public class Cl_RepositoryFactory
{
    public virtual I_Repository<I_Identifiable> CreateRepository(E_Repositories vrpRepository)
    {
        I_Repository<I_Identifiable> vrlRepository = null;
        switch (vrpRepository)
        {
            case E_Repositories.User:
                vrlRepository = new Cl_UserRepository() as I_Repository<I_Identifiable>;
                break;
        }
        return vrlRepository;
    }
}

枚举 E_Repositories:

public enum E_Repositories
{
    User
}

I_Identifiable 接口:

public interface I_Identifiable
{
    int Id { get; set; }
}

I_Repository 接口:

public interface I_Repository<T>
{
    T GetById(Guid id);
    T GetByQuery(Queue query);
    void Add(T item);
    void Remove(T item);
    void Update(T item);
}

Cl_UserRepository 类:

public class Cl_UserRepository : I_Repository<ClE_User>
{
    public void Add(ClE_User item)
    {
        MessageBox.Show("Created new User");
    }

    public ClE_User GetById(Guid id)
    {
        throw new NotImplementedException();
    }

    public ClE_User GetByQuery(Queue query)
    {
        throw new NotImplementedException();
    }

    public void Remove(ClE_User item)
    {
        throw new NotImplementedException();
    }

    public void Update(ClE_User item)
    {
        throw new NotImplementedException();
    }
}

还有 ClE_User 类:

public class ClE_User : I_Identifiable
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Password { get; set; }
}

问题是,为什么我使用 vrcRepository 得到空引用异常? vrlFactory.CreateRepository(E_Repositories.User); return null,我不知道为什么,请帮忙

【问题讨论】:

  • 因为您试图将 Cl_UserRepository 转换为 I_Repository&lt;I_Identifiable&gt; 并且这不是一回事,所以 ... as ... 位返回 null
  • 此外,您在此处使用的所有类型前缀(Cl_I_ 等)都会使您的代码难以阅读。
  • 如果I_Repository 上的泛型类型T 是协变的,它会起作用,但它不是也不能是因为T 被用作接口的输入。如果该演员确实有效,您可以将不是ClE_User 的东西传递给AddRemoveUpdate 的任何方法。
  • @DavidG 抱歉代码不可读,我只是尝试应用我公司采用的标准,对此无能为力。
  • 哇哦,那你们公司的标准真的很烂!随意告诉他们我说过:)

标签: c# .net nullreferenceexception factory factory-pattern


【解决方案1】:

CreateRepository 方法中尝试删除转换语句as I_Repository&lt;I_Identifiable&gt;。如果您的代码无法编译,则意味着Cl_UserRepositoryI_Repository&lt;I_Identifiable&gt; 不兼容。

否则,CreateRepository 方法的一切都是正确的

【讨论】:

    【解决方案2】:

    ClE_User 继承自 I_Identifiable,但 I_Repository&lt;ClE_User&gt; 不继承自 I_Repository&lt;I_Identifiable&gt;。就 C# 而言,这些是不同的接口。

    更详细地说,你有I_Repository&lt;I_Identifiable&gt; vrcRepository,理论上它应该是任何I_Identifiable 类型的I_Repository。因此,假设您将此成员初始化为其他成员,例如I_Repository&lt;ClE_SomethingOtherThanUser&gt;。但是你打电话给vrcRepository.Add(test)。这是行不通的,testClE_User

    现在,首先删除 as I_Repository&lt;I_Identifiable&gt; 部分,然后使其编译 make I_Repository 只是一个普通的哑非泛型接口,其方法采用 I_Identifiable 参数或返回 I_Identifiable 值。这可能不是你想要的,但它会编译。

    【讨论】:

      【解决方案3】:

      编辑

      我意识到枚举会触发。你是对的

      new Cl_UserRepository() as I_Repository

      CL_UserRepository 必须实现您尝试返回的接口,然后您根本不需要进行类型转换。对不起!我欠你一箱啤酒。

      【讨论】:

      • 不,OP 传入E_Repositories.User,这是开关中的枚举值之一。问题在于 as ... 演员表。
      • 你的答案的其余部分也是一个不好的建议 - 你不应该总是有一个默认情况,有很多很好的理由不这样做。你还欠 OP 一箱啤酒。
      • 不,没有。除非特定的 switch case 语句设置了一个布尔值,在这种情况下,你应该只使用 if else,你应该总是发送一个默认句柄来返回一个错误,除非你可以为你的返回设置一个默认值。在我见过的每个示例中,关闭没有默认值的开关都是不好的做法。至少,你总是会更好地记录发生的事情,因为你强迫自己考虑会发生什么,如果走向无穷大,一切都可能发生,应该发生什么。
      • 不会就默认情况与您争论,但请阅读this 进行更长时间的讨论。这绝对是不是不好的做法。至于你的其他评论,我真的不明白你在说什么。
      • 我看了看,几乎所有的建议都说,总是使用默认值。因为……它的好习惯……
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-07
      • 2011-03-13
      • 1970-01-01
      • 1970-01-01
      • 2016-02-01
      • 1970-01-01
      相关资源
      最近更新 更多