code4Better Ответов: 2

Как ограничить несколько функций linq/ запрос lampda для моей коллекции C#


Всем Привет,
У меня есть коллекция C#; скажем, личная информация,
List<PersonalInfo> _personalInfo =  new List<PersonalInfo>();

На данный момент я могу выполнять любые действия на эти коллекции с помощью LINQ/лямбда как
_personalInfo.Where or personalInfo.Count or _personalInfo.Select etc etc.

По соображениям безопасности я пытаюсь ограничить только конкретные запросы на _personalInfo, такие как Where, Take. Любой другой запрос в этом списке должен возвращать сообщение об ошибке "не поддерживается". Как мне этого добиться?
i am curious to know whether any way we can intercept query and check what is been used. ex:if the query is _personalInfo.Where(p=>p.age > 30) then, is there a way to know that it is a 'Where' query?


Что я уже пробовал:

Я попытался перехватить запрос и проверить, что такое команда запроса, но не смог этого сделать. Есть ли какой-то метод для достижения этого?

2 Ответов

Рейтинг:
8

OriginalGriff

Лучший способ сделать это-инкапсуляция: сделайте список a private входите в свой собственный класс и создавайте методы, позволяющие пользователям выполнять "разрешенные" действия. Инкапсулирующий класс никогда не возвращает инкапсулированную коллекцию во внешний мир, поэтому все взаимодействие может контролироваться вами.


code4Better

Спасибо @OriginalGriff. Я согласен с методами разоблачения, но мне любопытно узнать, можем ли мы каким-либо образом перехватить запрос и проверить, что было использовано. например:если запрос _personalInfo.Где(p=>p.возраст > 30) тогда есть ли способ узнать, что это запрос "где"?

Maciej Los

5ed!

code4Better

??

Рейтинг:
12

Maciej Los

Похоже, вы не понимаете того, что вам уже сказал OriginalGriff... Итак, я попытаюсь показать вам пример.

Представьте себе, что у вас есть Person класс:

public class Person
{
	private string personname = string.Empty;
	private DateTime dob = new DateTime(1900,1,1);
	
	public Person(){} //default empty constructor
	
	public Person(string _name, DateTime _dob)
	{
		personname = _name;
		dob = _dob;
	}
	
	public string Name
	{
		get => personname;
		set => personname = value;
	}
	
	public DateTime DateOfBorn
	{
		get => dob;
		set => dob = value;
	}
	
	public int Age => DateTime.Today.Year - this.dob.Year;
	
}


Теперь вы хотите создать "ограниченную коллекцию/список" из PersonС. Итак:
public class RestrictedCollection
{
	private List<Person> persons = null;

	public RestrictedCollection()
	{
		persons = new List<Person>()
		{
			new Person("Adam", new DateTime(1984,1,1)), new Person("Bart", new DateTime(1972,10,11)),
			new Person("Celine", new DateTime(1983,12,13)), new Person("Dijon", new DateTime(1986,3,17)),
			new Person("Eveline", new DateTime(1979,9,1)), new Person("Elisabeth", new DateTime(1985,5,21)),
			new Person("Ferdinand", new DateTime(1978,11,1)), new Person("Friderik", new DateTime(1979,7,31))
		};
	}
	
	public void Add(Person p)
	{
		if(!persons.Contains(p))
			persons.Add(p);
		else
			throw new InvalidOperationException($"'{p.Name}' born at {p.DateOfBorn.ToString("yyyy-MM-dd")} already exists!");
	}
	
	public void Remove(Person p)
	{
		if(persons.Contains(p))
			persons.Remove(p);
		else
			throw new InvalidOperationException($"'{p.Name}' born at {p.DateOfBorn.ToString("yyyy-MM-dd")} does not exist!");
	}
	
	public List<Person> Filter(Func<Person, bool> predicate)
	{
		List<Person> filtered = persons.Where(predicate).ToList();
		return filtered;
	}

}


Наконец, использование:
void Main()
{
	RestrictedCollection rc = new RestrictedCollection();
	//find persons 
	var result = rc.Filter(x=>x.Name.StartsWith("F"));

	//add new person
	Person p = new Person("Maciej", new DateTime(1969, 12, 6));
	rc.Add(p);
	result = rc.Filter(x=>x.Name==p.Name);
	
	//try to add existing person
	rc.Add(p); //throws InvalidOperation exception!
}


Примечание: В приведенном выше примере Filter метод действует как Where общее расширение List<T>.


code4Better

Большое вам спасибо, Мацей Лос. Очень ценю подробное объяснение и время, которое вы на это потратите. У меня есть один вопрос по вышеуказанным деталям,

От общественная список<человек&ГТ; фильтр(Функ&ЛТ;человек, булевых=""&ГТ; способ предиката), это можно понять, как startswith' - фактический запрос, что называется? Я пробовал разные варианты, и я могу получить имя класса как "person" и аргумент как "x", но не смог найти ни одного варианта, который даст запрос "StartsWith". Не могли бы вы мне в этом помочь?

Maciej Los

Извините, я вас не понимаю... Filter метод был создан только для примера.
Если вы хотите разоблачить StartsWith метод, вы можете это сделать! Вы также можете использовать любой другой метод, например Select, Where, прием. Тогда вы будете на 100% уверены, какой метод был вызван. Вы можете удалить Filter универсальный метод.

Помните, что вы можете измениться RestrictedCollection класс для ваших нужд.

code4Better

Извините, если я вас смутил. В основном то, что мой вопрос был
здесь я вызываю SomeMethod() несколькими способами, как показано на рисунке

1. ру.Метода someMethod(х=>У Х.Имя.StartsWith("F"));
2. ру.Метода someMethod(х => У Х.Имя."Равно" ("Уровне"));
3. ру.Метода someMethod(х => У Х.Имя.Любой());

// Какая-то имплементация метода. Метод проверяет, является ли выполненный запрос утвержденным запросом или нет
частная метода someMethod типа bool (Функ&ЛТ;человек, булевых=""> В предикате)
{
//если запрос совпадает с StartsWith, верните true

{логика идентификации запроса начинается с}

//если запрос совпадает с равным, верните false

{логика идентификации запроса равна}

//если запрос совпадает с любым, верните false

{логика идентификации запроса любая}

... И так далее
}

Поэтому здесь я хочу использовать метод, который ограничит некоторые запросы и разрешит некоторые из них в зависимости от утвержденного списка запросов. В приведенном выше примере я разрешаю только "StartsWith" в качестве утвержденного запроса. Остальные не утверждены. Надеюсь, на этот раз я смогу объяснить лучше.

Maciej Los

Как я уже говорил, Вы должны предоставить методы StartsWith, Equals и т. д., а не использовать один общий метод (в вашем случае это SomeMethod). Другого способа достичь этого нет, если только вы не предоставите универсальный метод, в котором вы передадите имя метода для вызова.
Видеть: Как использовать деревья выражений для построения динамических запросов (C#) | Microsoft Docs[^]

code4Better

Большое вам спасибо, Мацей.

Maciej Los

Всегда пожалуйста.