При наследовании переопределяет метод с теми же параметрами, но разными типами возвращаемых данных - PullRequest
0 голосов
/ 08 февраля 2012

Я нашел несколько других вопросов, которые касаются этой темы, но я просто не могу понять, что это правильно для моей конкретной ситуации.Я чувствую, что уже где-то наткнулся на ответ, но просто не осознал этого.Мне просто нужно подтолкнуть в правильном направлении, чтобы закончить это.

Я создаю собственный ASP.NET RoleProvider.Поскольку он наследуется от RoleProvider, я должен переопределить открытую строку [] GetAllRoles ().Однако я обнаружил, что строка [] недостаточна, поэтому я создал новый класс с именем ProjectRole и заставил GetAllRoles () возвращать List.

Моя причина в том, что моя пользовательская таблица ролей содержит больше данных, чем просто имена (идентификаторы)именами, описаниями и т. д. на нескольких языках, таких как DescriptionE, DescriptionJ и т. д.), и я хотел бы вернуть все о роли, а не просто имя.

Итак, вот мы (сокращенно для краткостиради)

public class ProjectRoleProvider : RoleProvider
{
    public override string[] GetAllRoles()
    {
        throw new NotImplementedException();
    }

    public override List<ProjectRole> GetAllRoles()
    {
        List<ProjectRole> rolelist = new List<ProjectRole>();

        SqlConnection conn = new SqlConnection(connstring);
        SqlCommand cmd = new SqlCommand("sprocGetAllRoles", conn);
        cmd.CommandType = CommandType.StoredProcedure;

        conn.Open();
        using (SqlDataReader reader = cmd.ExecuteReader())
        {
            if (reader.HasRows == true)
            {
                while (reader.Read())
                {
                    ProjectRole somerole = new ProjectRole();
                    somerole.ProjectRoleID = reader.GetGuid(reader.GetOrdinal("ProjectRoleID"));
                    somerole.RoleNameE = reader.GetString(reader.GetOrdinal("RoleNameE"));
                    somerole.RoleNameJ = reader.GetString(reader.GetOrdinal("RoleNameJ"));
                    somerole.DescriptionE = reader.GetString(reader.GetOrdinal("DescriptionE"));
                    somerole.DescriptionJ = reader.GetString(reader.GetOrdinal("DescriptionJ"));
                    rolelist.Add(somerole);
                }
            }
            reader.Close();
        }
        conn.Close();

        return rolelist;
    }

    public class ProjectRole
    {
       private Guid _projectRoleID = Guid.Empty;
       private string _roleNameE = String.Empty;
       private string _roleNameJ = String.Empty;
       private string _descriptionE = String.Empty;
       private string _descriptionJ = String.Empty;

       //public properties to interact with the private fields

       public ProjectRole()
       {
       }
    }
}

Меня беспокоит то, что я могу просто оставить строку [] GetAllRoles () в качестве неосуществленной и назвать мой список GetAllRoles () как-то еще, например, GetRoles(), а потом все в порядке.Но тогда действительно неясно, когда вы делаете вызов, и вы видите два варианта с Intellisense («какие из них я использую?»).Да, я мог бы использовать комментарии XML и сказать: «Эй, не используйте это, используйте вместо этого GetRoles», но я бы предпочел просто переопределить также тип возвращаемого значения и покончить с этим.

Ответы [ 2 ]

4 голосов
/ 08 февраля 2012

Код, который вы представили, не скомпилируется, поскольку вы пытаетесь перегрузить только типом возвращаемого значения. Это неверно C #. (As пытается «переопределить» сигнатуру метода, которая не указана в базовом классе.)

Но нет, в общем, вы не можете этого сделать. В самом деле, было бы плохо, если бы вы могли , потому что точка наследования заключается в том, что вызывающая сторона, которая знает только о типе base , должна иметь возможность написать:

string[] roles = provider.GetUserRoles();

Если они не могут этого сделать и получить разумный результат, значит, вы просто не выполняете контракт RoleProvider.

Вы, вероятно, должны либо , а не быть производным от RoleProvider, во-первых (если вы не хотите, чтобы ваш класс использовался как a RoleProvider), либо вам следует переопределите GetAllRoles обычным способом и включите другой метод с другим именем, который могут использовать вызывающие, которые do знают о вашем конкретном подклассе (и которым нужна дополнительная информация).

Я бы больше сочувствовал, если бы вы пытались переопределить метод, объявленный для возврата одного типа, чтобы дать более конкретный , но все еще совместимый возвращаемый тип; это поддерживается Java, но не C #. Для интерфейсов вы можете использовать явную реализацию интерфейса в этом случае, но уловка не работает для абстрактных классов.

2 голосов
/ 08 февраля 2012

В принципе невозможно изменить тип возвращаемого значения переопределения.

Что произойдет, если вы напишите

string[] roles = ((RoleProvider)new ProjectRoleProvider()).GetAllRoles();

Вместо этого вы должны пометить переопределение как [Obsolete] (примечаниеэто вызовет предупреждение компилятора).

Однако я бы порекомендовал переименовать вашу версию в GetRolesDetail(), чтобы более наглядно продемонстрировать разницу.

...