Я давно хотел что-то подобное - многие страницы, которые мы пишем, могли бы быть сгенерированы младшим разработчиком, если бы им не нужно было писать кучу запросов; и, в любом случае, это один и тот же базовый шаблонный запрос - зачем им писать их для каждого контроллера, когда большая часть их работы состоит в том, чтобы получить контент? Я использую C #, поэтому мне не приходится иметь дело с управлением памятью. Почему HTML-кодер должен иметь дело с деталями запроса?
Существует способ, позволяющий неявно загружать данные асинхронно в View. , Сначала вы определяете класс, который выражает, какие данные вы хотите. Затем в верхней части каждого представления создайте экземпляр этого класса. Вернувшись в контроллер, вы можете найти представление, которое, как вы знаете, собираетесь использовать, открыть его, а затем скомпилировать этот класс . Затем вы можете использовать его, чтобы получить данные, необходимые представлению, асинхронно, в контроллере, как это обеспечивает MVC. Наконец, передайте его с помощью ViewModel в View, как предписывает MVC, и, через некоторую хитрость, у вас будет View, который объявляет, какие данные он собирается использовать.
Вот StoryController. Младшие разработчики пишут истории в виде простых файлов .cshtml, не зная, что такое контроллер, база данных или LINQ:
public class StoryController : BaseController
{
[OutputCache(Duration=CacheDuration.Days1)]
// /story/(id)
public async Task<ActionResult> Id(string id = null)
{
string storyFilename = id;
// Get the View - story file
if (storyFilename == null || storyFilename.Contains('.'))
return Redirect("/"); // Disallow ../ for example
string path = App.O.AppRoot + App.HomeViews + @"story\" + storyFilename + ".cshtml";
if (!System.IO.File.Exists(path))
return Redirect("/");
return View(storyFilename);
Пока все, что нужно сделать, это получить файл View на основе URL, что-то вроде Веб-формы (за исключением внутри MVC и с использованием Razor). Но мы хотим показать некоторые данные - в нашем случае, людей и проекты, которые накапливаются в базе данных - с некоторыми стандартными ViewModels и Partials. Давайте определимся как и скомпилируем это. (Обратите внимание, что в моем случае ConservX является основным пространством имен Project).
public async Task<ActionResult> Id(string id = null)
{
string storyFilename = id;
// 1) Get the View - story file
if (storyFilename == null || storyFilename.Contains('.'))
return Redirect("/"); // Disallow ../ for example
string path = App.O.AppRoot + App.HomeViews + @"story\" + storyFilename + ".cshtml";
if (!System.IO.File.Exists(path))
return Redirect("/");
// 2) It exists - begin parsing it for StoryDataIds
var lines = await FileHelper.ReadLinesUntilAsync(path, line => line.Contains("@section"));
// 3) Is there a line that says "new StoryDataIds"?
int i = 0;
int l = lines.Count;
for (; i < l && !lines[i].Contains("var dataIds = new StoryDataIds"); i++)
{}
if (i == l) // No StoryDataIds defined, just pass an empty StoryViewModel
return View(storyFilename, new StoryViewModel());
// https://stackoverflow.com/questions/1361965/compile-simple-string
// https://msdn.microsoft.com/en-us/library/system.codedom.codecompileunit.aspx
// https://msdn.microsoft.com/en-us/library/system.codedom.compiler.codedomprovider(v=vs.110).aspx
string className = "__StoryData_" + storyFilename;
string code = String.Join(" ",
(new[] {
"using ConservX.Areas.Home.ViewModels.Storying;",
"public class " + className + " { public static StoryDataIds Get() {"
}).Concat(
lines.Skip(i).TakeWhile(line => !line.Contains("};"))
).Concat(
new[] { "}; return dataIds; } }" }
));
var refs = AppDomain.CurrentDomain.GetAssemblies();
var refFiles = refs.Where(a => !a.IsDynamic).Select(a => a.Location).ToArray();
var cSharp = (new Microsoft.CSharp.CSharpCodeProvider()).CreateCompiler();
var compileParams = new System.CodeDom.Compiler.CompilerParameters(refFiles);
compileParams.GenerateInMemory = true;
compileParams.GenerateExecutable = false;
var compilerResult = cSharp.CompileAssemblyFromSource(compileParams, code);
var asm = compilerResult.CompiledAssembly;
var tempType = asm.GetType(className);
var ids = (StoryDataIds)tempType.GetMethod("Get").Invoke(null, null);
using (var db... // Fetch the relevant data here
var vm = new StoryViewModel();
return View(storyFilename, vm);
}
Это большая часть работы. Теперь младшие разработчики могут просто объявить необходимые данные следующим образом:
@using ConservX.Areas.Home.ViewModels.Storying
@model StoryViewModel
@{
var dataIds = new StoryDataIds
{
ProjectIds = new[] { 4 }
};
string title = "Story Title";
ViewBag.Title = title;
Layout = "~/Areas/Home/Views/Shared/_Main.cshtml";
}
@section css {
...
As others have pointed out, there are many kinds of "null" under Cocoa/Objective C. But one further thing to note is that [title isKindOfClass:[NSNull class]] is pointlessly complex since [NSNull null] is documented to be a singleton so you can just check for pointer equality. See Topics for Cocoa: Using Null.
So a good test might be:
if (title == (id)[NSNull null] || title.length == 0 ) title = @"Something";
Note how you can use the fact that even if title is nil, title.length will return 0/nil/false, ie 0 in this case, so you do not have to special case it. This is something that people who are new to Objective C have trouble getting used to, especially coming form other languages where messages/method calls to nil crash.
Если такого рода вещи еще не существуют, вы можете создать категорию NSString:
@interface NSString (TrucBiduleChoseAdditions)
- (BOOL)isEmpty;
@end
@implementation NSString (TrucBiduleChoseAdditions)
- (BOOL)isEmpty {
return self == nil || [@"" isEqualToString:self];
}
@end
Если вы хотите протестировать все пустые / пустые объекты (например, пустые строки или пустые массивы / наборы), вы можете использовать следующее:
static inline BOOL IsEmpty(id object) {
return object == nil
|| ([object respondsToSelector:@selector(length)]
&& [(NSData *) object length] == 0)
|| ([object respondsToSelector:@selector(count)]
&& [(NSArray *) object count] == 0);
}
См. Следующие статьи на этом сайте:
Я думаю, ваша ошибка связана с чем-то другим, так как вам не нужно выполнять дополнительную проверку.
Также см. этот связанный вопрос: Правильная проверка пустого текстового столбца sqlite
это так же просто, как
if([object length] >0)
{
// do something
}
помните, что в объекте C, если объект равен нулю, он возвращает 0 в качестве значения.
Это даст вам как пустую строку, так и длину 0 строка.