#c# #generics
#c# #универсальные
Вопрос:
Я хочу создать универсальный метод сохранения, который должен работать следующим образом;
Entity.User.User user = new Entity.User.User();
user.FirstName = "A";
user.LastName = "B";
user.UserName = "C";
user.Save();
public class User : BaseClass<User>
{
public virtual int UserId { get; set; }
public virtual string UserName { get; set; }
public virtual string Password { get; set; }
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
//I WANT THIS METHOD TO BE GENERIC UNDER BASE CLASS
//public void Save()
//{
// CREATE.New(this);
//}
}
public partial class BaseClass<T>
{
public void Save(this T x)
{
CREATE<T>.New(x);
}
}
public class CREATE<T>
{
public static void New(T x)
{
//some code
}
}
но я получаю сообщение об ошибке «Метод расширения должен быть определен в неродовом статическом классе»
ищу руководство по управлению этой работой. Спасибо
Комментарии:
1. методы расширения также не могут быть виртуальными; что вы пытаетесь сделать? если это базовый класс, то он
this
просто обычныйthis
— вthis T x
; простоCREATE<T>.New(this)
.CREATE<T>
кстати, ужасное имя.2. Извините, но разве это не циклическая ссылка?
public class User : BaseClass<User>
3. Я исправил виртуальный. обновлено
4. Класс CREATE должен быть статическим, если в нем есть статический метод.
5. Ключевое слово @Marc ‘this’ недопустимо в статическом свойстве, статическом методе или инициализаторе статического поля
Ответ №1:
Чтобы совместно использовать метод сохранения со всеми вашими «сущностями», вам не нужен ни общий родительский класс, ни методы расширения.
это всего лишь простое наследство:
public class User : BaseClass
{
public int UserId { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class BaseClass
{
public void Save()
{
//put save logic here. Should match for all
//concrete implementations of BaseClass
}
}
теперь вы просто можете вызвать
User user = new User();
user.FirstName = "A";
user.LastName = "B";
user.UserName = "C";
user.Save();
Обычно вы хотите, чтобы каждый класс в вашем дереве наследования сохранял свои собственные атрибуты, а затем вызывал родительскую функцию save(), чтобы вам не приходилось повторять это снова и снова.
Конкретная реализация зависит от того, как вы сохраняете. Если это просто сериализация, вы могли бы придерживаться одного глобального метода сохранения в базовом классе, и дочерним элементам не нужно предоставлять какую-либо реализацию в save().
т. е. для построения строки вы могли бы сделать что-то вроде этого: Таким образом, КАЖДЫЙ класс просто предоставляет ту часть, за которую он отвечает:
public class User : BaseClass
{
public string UserName { get; set; }
public string Password { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public override String Save(){
s = base.Save(); //recall base.Save() as long as its not the topmost-entity
//attach Username, password, firstname, lastname
return s;
}
}
public class BaseClass
{
public int Id { get; set; }
public virtual String Save()
{
String s = "";
//attach id to s
return s;
}
}
вызов userInstance.Save()
сейчас вернет вам строку со всеми переменными, включая идентификатор базового класса. (Это становится удобным, если у вас сложное дерево, где каждый класс просто должен отвечать за свои собственные атрибуты.)
На практике вы бы создали не строку, а, возможно, XML-элемент или подготовленную инструкцию, готовую к запуску с базой данных.
Комментарии:
1. извините, если я что-то пропустил, но где пользователь в качестве входных данных? и как мне создать логику, над которой я не знаю, над каким типом класса я работаю. не могли бы вы заполнить внутри сохранения, чтобы я лучше понял.
2. @Mert вам не нужен пользователь в качестве входных данных. он унаследует метод, как и любой другой метод. Вы всегда можете узнать, с каким конкретным классом вы работаете (
if (this is User)
), И конкретная реализация сохранения зависит от того, как вы сохраняете.3. Это сработало, но я потерял всю общую функциональность, я выясню, наносит ли это какой-либо вред моему общему решению. Спасибо
4. Я хотел бы услышать от вас комментарий о решении Марка. Кажется, вы, ребята, более опытны в этом вопросе.
Ответ №2:
С вашим общим подходом, я думаю, что вам нужно, это:
public partial class BaseClass<T>
{
public virtual void Save()
{
// only support the T : BaseClass<T> scenario, so
// we expect "this" to be a T
CREATE<T>.New((T)(object)this);
}
}
Комментарии:
1. Я попробовал ваше решение, и оно сработало. кроме того, я не потерял общую функциональность, которая выглядит как лучшее решение. спасибо, я новичок в дженериках, поэтому мне требуется время, чтобы полностью разобраться. Спасибо
Ответ №3:
Вам нужно изменить класс CREATE на:
public static class CREATE
{
public static void New<T>(this T x)
{
//some code
}
}
Это ваш метод расширения, они должны быть в статическом неродовом классе. Как и ошибка, на которую вам указали.
И вам нужно изменить Save
метод на:
public void Save(T x)
{
x.Save();
}
Это вызывает метод сохранения расширения. Поскольку базовый класс является универсальным и нестатическим, он не может содержать методы расширения.
Комментарии:
1. И он должен изменить метод сохранения на:
public void Save() { CREATE.New<T>(this); }
2. добавление этого при новой созданной ошибке this ; Метод расширения должен быть определен в неродовом статическом классе И удаление <T> из CREATE<T> вызывает эту ошибку; Не удалось найти тип или имя пространства имен ‘T’ (вам не хватает директивы using или ссылки на сборку?)