在C#和Visual Studio 2005年大会之间循环引用 [英] Circular reference between Assemblies in C# and Visual Studio 2005

查看:87
本文介绍了在C#和Visual Studio 2005年大会之间循环引用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在努力使所有应用程序的单层分层/ n层设计标准化。

I am working hard to standardize one single way of Layered/n-Tiered design of my all applications.

我试图让所有应用程序分层。

I am trying to make all my applications 5 tiered.

代码:

假设我正在为用户开发具有登录/注销功能的应用程序。我在VS2005解决方案下创建4个项目。每个项目是上4层之一。
我设计我的业务对象类如下: -

Suppose I am developing an application with a log-in/log-out capability for users. I am creating 4 projects under a VS2005 solution. Each project is for one of the upper 4 layers. I am designing my Business Object class as follows:-

public class User
{
    private string _username;
    public string Username
    {
        get { return _username; }
        set { _username = value; }
    }

    private string _password;
    public string Password
    {
        get { return _password; }
        set { _password = value; }
    }

    public User()
    {
    }

    public bool LogIn(String username, String password)
    {
        bool success = false;

        if (UserMapper.UsernameExists(username))
        {
            success = UserMapper.UsernamePasswordExists(username, password);
        }
        else
        {
            //do nothing
        }

        return success;
    }

    public bool LogOut()
    {
           bool success;
        //----some logic
           return success;
    }

    public static User GetUserByUsername(string username)
    {
        return UserMapper.GetUserByUsername(username);
    }

    public static UserCollection GetByUserTypeCode(string code)
    {
        return UserMapper.GetByUserTypeCode(code);
    }
}

这是我给我的对象一些功能匹配现实世界场景。这里GetByUsername()和GetByUserTypeCode()是getter函数。这些函数不匹配真实世界的逻辑。 Coz,在现实世界中,用户从不按用户名获取或通过UserTypeCode获取。因此,这些函数保持静态。

This is how I am giving my objects some functionality that matches the real-world scenario. Here GetByUsername() and GetByUserTypeCode() are getter functions. These functions does't match a real-world logic. Coz, in real-world, a User never "Gets by Username" or "Gets by UserTypeCode". So these functions are kept static.

我的类为OR Mapper图层如下: -

My class for O-R Mapper layer is as follows:-

public static class UserMapper
{
    public static bool UsernameExists(String username)
    {
        bool exists = false;

        if (UserDA.CountUsername(username) == 1)
        {
            exists = true;
        }

        return exists;
    }

    public static bool UsernamePasswordExists(String username, String password)
    {
        bool exists = false;

        if (UserDA.CountUsernameAndPassword(username, password) == 1)
        {
            exists = true;
        }

        return exists;
    }
}

最后,DA类如下:

public static class UserDA
{
    public static int CountUsername(string username)
    {
        int count = -1;

        SqlConnection conn = DBConn.Connection;

        if (conn != null)
        {
            try
            {
                SqlCommand command = new SqlCommand();
                command.Connection = conn;
                command.CommandText = @"SELECT COUNT(*) 
                                FROM User 
                                WHERE User_name = @User_name";
                command.Parameters.AddWithValue("@User_name", username);

                command.Connection.Open();
                object idRaw = command.ExecuteScalar();
                command.Connection.Close();

                if (idRaw == DBNull.Value)
                {
                    count = 0;
                }
                else
                {
                    count = (int)idRaw;
                }
            }
            catch (Exception ex)
            {
                count = -1;
            }
        }

        return count;
    }  

    public static int CountUsernameAndPassword(string username, string password)
    {
        int count = 0;

        SqlConnection conn = DBConn.Connection;

        if (conn != null)
        {
            try
            {
                SqlCommand command = new SqlCommand();
                command.Connection = conn;
                command.CommandText = @"SELECT COUNT(*) 
                                FROM User 
                                WHERE User_name = @User_name AND Pass_word = @Pass_word";
                command.Parameters.AddWithValue("@User_name", username);
                command.Parameters.AddWithValue("@Pass_word", password);

                command.Connection.Open();
                object idRaw = command.ExecuteScalar();
                command.Connection.Close();

                if (idRaw == DBNull.Value)
                {
                    count = 0;
                }
                else
                {
                    count = (int)idRaw;
                }
            }
            catch (Exception ex)
            {
                count = 0;
            }
        }

        return count;
    }

    public static int InsertUser(params object[] objects)
    {
        int count = -1;

        SqlConnection conn = DBConn.Connection;

        if (conn != null)
        {
            try
            {
                SqlCommand command = new SqlCommand();
                command.Connection = conn;
                command.CommandText = @"INSERT INTO User(ID, User_name, Pass_word, RegDate, UserTypeCode, ActualCodeOrRoll) 
                                                            VALUES(@ID, @User_name, @Pass_word, @RegDate, @UserTypeCode, @ActualCodeOrRoll)";
                command.Parameters.AddWithValue("@ID", objects[0]);
                command.Parameters.AddWithValue("@User_name", objects[1]);
                command.Parameters.AddWithValue("@Pass_word", objects[2]);
                command.Parameters.AddWithValue("@RegDate", objects[3]);
                command.Parameters.AddWithValue("@UserTypeCode", objects[4]);
                command.Parameters.AddWithValue("@ActualCodeOrRoll", objects[5]);

                command.Connection.Open();
                count = command.ExecuteNonQuery();
                command.Connection.Close();
            }
            catch (Exception ex)
            {
                count = -1;
            }
        }

        return count;
    }

    public static SqlDataReader GetUserByUsername(string username)
    {
        SqlDataReader dataReader = null;

        SqlConnection conn = DBConn.Connection;

        if (conn != null)
        {
            try
            {
                SqlCommand command = new SqlCommand();
                command.Connection = conn;
                command.CommandText = @"SELECT * FROM User WHERE User_name = @User_name";
                command.Parameters.AddWithValue("@User_name", username);

                command.Connection.Open();

                dataReader = command.ExecuteReader(CommandBehavior.CloseConnection);

            }
            catch (Exception ex)
            {
                dataReader.Close();
                dataReader.Dispose();
            }
        }

        return dataReader;
    }

    public static SqlDataReader GetUserByUserTypeCode(string userTypeCode)
    {
        SqlDataReader dataReader = null;

        SqlConnection conn = DBConn.Connection;

        if (conn != null)
        {
            try
            {
                SqlCommand command = new SqlCommand();
                command.Connection = conn;
                command.CommandText = @"SELECT * FROM User WHERE UserTypeCode = @UserTypeCode";
                command.Parameters.AddWithValue("@UserTypeCode", userTypeCode);

                command.Connection.Open();

                dataReader = command.ExecuteReader(CommandBehavior.CloseConnection);

            }
            catch (Exception ex)
            {
                dataReader.Close();
                dataReader.Dispose();
            }
        }

        return dataReader;
    }
}



如果任何人仔细检查这些类,他可以理解,OR映射器层需要BusinessObject-layer的引用。 BusinessObject- layer还需要一个OR Mapper-layer的引用。

If anyone closely examine the these classes he can understand that, O-R Mapper layer needs the reference of BusinessObject-layer. BusinessObject- layer also needs a reference of O-R Mapper-layer.

这将创建一个循环依赖。

This should create a circular dependency.

如何避免此问题?

有人建议使用纯数据传输对象(DTO)。但是,据我所知,根据OOP,现实世界对象的属性和功能应该被分组在一起作为一个类。如果我使用DTO,那么如何将功能封装到类中?此外,我创建另一个类没有任何属性(BO)。对我来说,这是违反OOP在两个方面。如果我这样做,那么在这个世界是什么是OOP?相同的答案可以应用于UserManager类。

Someone suggested using plain Data Transfer Objects (DTO). But, as far as I know, according to OOP, attributes and functionality of a real-world object should be grouped together as a class. If I use DTO then how can I encapsulate functionality into a class? Moreover I am creating another class without any attribute (BO). To me that is breach of OOP in both ways. If I do so, then what is OOP for in this world? The same answer can be applied for "UserManager" classes.

我发现了一个博客

它讨论了实现接口。定义一个单独的接口,在BusinessObject中的数据类中实现它,并在BusinessObject和OR-Mapper层中的接口上进行编程。

It discusses about implementing interfaces. Define a separate interface, implement it in your data class in the BusinessObject and program against your interface in the BusinessObject and in the OR-Mapper layer.

但我不能

任何人都可以用一个实际例子告诉我。

Can anyone show me that with a practical example?

推荐答案

p>我认为有几件事情你可以做,一起可以帮助您的设计。我也认为您可能想阅读依赖注入,或许可以提供更好的设计

I think there are a few things you can do that together could help with your design. I also think that you might want to read up on Dependency Injection as perhaps providing a better design pattern for what you want to do.


  • 首先,从 User 类中删除 static 方法,创建'用户,因此最好只保留在 UserMapper

  • First, remove the static methods from your User class, since they 'create' users, and therefore are best just left on the UserMapper.

仍然有许多方法可能使用 User 类中的 UserMapper 功能。创建支持 UserNameExists UserNamePasswordExists 的接口 IUserLookup $ c> methods;将此界面置于与 User 类相同的项目中。

After that, there will still be a number of methods potentially that use UserMapper functionality from the User class. Create an interface IUserLookup (or something) that supports the UserNameExists and UserNamePasswordExists methods; put this interface in the same project as the User class.

实现 IUserLookup UserMapper 类中,然后将它注入到 User 通过构造函数使用静态方法创建的实例,所以基本上,如 UserMapper 创建用户对象,

Implement the IUserLookup on the UserMapper class, and then 'inject' it into the User class instances it creates with the static methods through a constructor, so basically, as the UserMapper creates User objects, it gives them a reference to the IUserLookup interface that it implements itself.

这样, User 只使用在同一个解决方案中的 IUserLookup 上的方法,因此不需要引用。 UserMapper 引用此解决方案,因此可以创建 User 对象并实现 IUserLookup 接口。

In this way, User only uses methods on IUserLookup, which is in the same solution, so no reference needed. And UserMapper references this solution, so it can create User objects and implement the IUserLookup interface.

这篇关于在C#和Visual Studio 2005年大会之间循环引用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆