PostSharp 5.1 will focus on providing support for .NET Standard 2.0 and .NET Core 2.0. Our objective is to port the PostSharp compiler itself to .NET Standard 2.0 so that we can compile .NET Standard and .NET Core applications natively, without cross-compilation. PostSharp 5.1 will still only support Windows as the only build platform.
اشتراکها
اشتراکها
Entity Framework Core 2.0 منتشر شد
Today we are releasing the final version of Entity Framework Core 2.0, alongside .NET Core 2.0 and ASP.NET Core 2.0.
Entity Framework (EF) Core is the lightweight, extensible, and cross-platform version of Entity Framework, the popular Object/Relational Mapping (O/RM) framework for .NET.
نظرات مطالب
ASP.NET MVC #12
ممنون؛ به سایتی که معرفی کردید رفتم و هر دو فایل jquery.price_format.2.0.js
و jquery.price_format.2.0.min.js
رو به پروژه اضافه کردم. تو view خطوط زیر رو نوشتم:
<script src="../../Scripts/jquery-1.9.1.min.js" type="text/javascript"></script> <script src="../../Scripts/jquery.price_format.2.0.js" type="text/javascript"></script>
ولی باز هم نتیجه نگرفتم. میشه لطف کنید راهنمائیم کنید که چطور از اون مثال استفاده کنم؟
Microsoft's Ryan Molden said : that disallowing non-Microsoft extensions is deliberate.
We don't prevent you from INSTALLING a package to Express ,since that just means 'writing some bits into the registry ', but it will never successfully load. As I mentioned in the other post, this is not a technological limitation, it is a business decision, one I disagree with, but I don't make these decisions
We don't prevent you from INSTALLING a package to Express ,since that just means 'writing some bits into the registry ', but it will never successfully load. As I mentioned in the other post, this is not a technological limitation, it is a business decision, one I disagree with, but I don't make these decisions
تا اینجا با کمک توابع توانستیم PowerShell را به اصطلاح extend کنیم. نوع دیگر دستورات، command letها هستند. این نوع دستورات را با کمک یک زبان داتنتی میتوانیم ایجاد کنیم. به این نوع دستورات complied cmdlet گفته میشود. در بیشتر مواقع با کمک advanced functionها میتوانید بیشتر کارها را انجام دهید؛ چراکه به صورت مستقیم امکان استفاده از داتنت را درون PowerShell دارید. اما شاید ترجیح دهید از سیشارپ یا دیگر زبانها داتنتی برای ایجاد یک تابع استفاده کنید.
نحوهی ایجاد یک cmdlet با کمک #C
ابتدا یک دایرکتوری جدید را ایجاد کرده و درون آن یک پروژهی از نوع class library را ایجاد کنید. سپس پکیج PowerShellStandard.Library را درون پروژه ایجاد شده با کمک dotnet cli به پروژه اضافه کنید:
mkdir ps_cmdlet_with_csharp && cd "$_" dotnet new classlib dotnet add package PowerShellStandard.Library mv Class1.cs GetHelloCommand.cs
namespace ps_cmdlet_with_csharp; using System.Management.Automation; [Cmdlet(VerbsCommon.Get, "Hello")] public class GetHelloCommand : PSCmdlet { [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true)] public string Name { get; set; } protected override void BeginProcessing() { WriteObject("Start processing"); } protected override void ProcessRecord() { WriteObject("Hello " + Name); } protected override void EndProcessing() { WriteObject("End processing"); } }
using System.Collections.ObjectModel; using System.Management.Automation.Host; namespace System.Management.Automation { public abstract class PSCmdlet : Cmdlet { protected PSCmdlet(); public PSEventManager Events { get; } public PSHost Host { get; } public CommandInvocationIntrinsics InvokeCommand { get; } public ProviderIntrinsics InvokeProvider { get; } public JobManager JobManager { get; } public JobRepository JobRepository { get; } public InvocationInfo MyInvocation { get; } public PagingParameters PagingParameters { get; } public string ParameterSetName { get; } public SessionState SessionState { get; } public PathInfo CurrentProviderLocation(string providerId); public Collection<string> GetResolvedProviderPathFromPSPath(string path, out ProviderInfo provider); public string GetUnresolvedProviderPathFromPSPath(string path); public object GetVariableValue(string name); public object GetVariableValue(string name, object defaultValue); } }
PS /> dotnet build PS /> Import-Module ./bin/Debug/net7.0/ps_cmdlet_with_csharp.dll
PS /> Get-Command -Module ps_cmdlet_with_csharp CommandType Name Version Source ----------- ---- ------- ------ Cmdlet Get-Hello 1.0.0.0 ps_cmdlet_with_csharp
namespace ps_cmdlet_with_csharp; using System.Management.Automation; [Cmdlet(VerbsCommon.Get, "Hello")] public class GetHelloCommand : PSCmdlet { // as before } [Cmdlet(VerbsCommon.Get, "Greetings")] public class GetGreetingsCommand : PSCmdlet { [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true)] public string Name { get; set; } protected override void BeginProcessing() { WriteObject("Start processing"); } protected override void ProcessRecord() { WriteObject("Greetings " + Name); } protected override void EndProcessing() { WriteObject("End processing"); } }
Import-Module: Invalid assembly public key.
<Project Sdk="Microsoft.NET.Sdk"> <!-- other tags --> <ItemGroup> <Compile Include="./GetHelloCommand.cs" /> </ItemGroup> </Project>
PS /> Get-Command -Module ps_cmdlet_with_csharp CommandType Name Version Source ----------- ---- ------- ------ Cmdlet Get-Greetings 1.0.0.0 ps_cmdlet_with_csharp Cmdlet Get-Hello 1.0.0.0 ps_cmdlet_with_csharp
یک مثال تکمیلی
درون یک کلاس Cmdlet، امکان استفاده از تمامی annotationهایی را که در قسمت قبل بررسی کردیم، اینجا نیز در اختیار داریم؛ بنابراین نیاز به توضیح مجدد آن نیست. در ادامه میخواهیم یک دستور را با عنوان Push-SlackMessage تهیه کنیم که کار ارسال یک پیام را به یک کانال Slack، انجام میدهد:
namespace ps_cmdlet_with_csharp; using System.Management.Automation; using System.Net.Http.Headers; [Cmdlet(VerbsCommon.Push, "SlackMessage")] [Alias("ssm")] [OutputType(typeof(string))] public class SlackMessageCommand : PSCmdlet { [Parameter(Mandatory = true)] [Alias("m")] public string Message { get; set; } [Parameter(Mandatory = true)] [Alias("t")] [ValidatePattern(@"xoxp-[0-9]{11}-[0-9]{12}-[0-9]{13}-[0-9a-zA-Z]{32}")] public string Token { get; set; } [Parameter(Mandatory = true)] [Alias("cid")] public string ChannelID { get; set; } protected async override void ProcessRecord() { base.ProcessRecord(); try { using var client = new HttpClient(); client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", this.Token); var values = new Dictionary<string, string> { { "channel", this.ChannelID }, { "text", this.Message } }; var content = new FormUrlEncodedContent(values); var response = await client.PostAsync("https://slack.com/api/chat.postMessage", content); var responseString = await response.Content.ReadAsStringAsync(); WriteObject("Message sent"); } catch (Exception ex) { WriteObject(ex.Message); } } }
یک نکته در مورد ایمپورت کردن ماژولها
دستوراتی که تاکنون ایجاد کردیم (هم توابع و هم compiled cmletها) برای اجرا باید یکبار درون حافظه قرار بگیرند و سپس امکان اجرای آنها را خواهیم داشت. دلیل آن نیز این است که همه چیز درون سشن جاری انجام خواهد شد و به محض بستن آن، تغییرات نیز ار حافظه خارج خواهند شد. یعنی برای command letی که ایجاد کردیم، با هربار باز کردن یک سشن جدید مجبور خواهیم بود که مجدداً آن را ایمپورت کنیم. برای رفع این مشکل میتوانیم از پروفایلها استفاده کنیم. توسط پروفایل، امکان سفارشیسازی شل را خواهیم داشت. پروفایل در واقع یک اسکریپت PowerShell است که به محض اجرای PowerShell فراخوانی خواهد شد. بنابراین درون پروفایل این فرصت را خواهیم داشت تا متغیرها، ماژولها، aliaseها و… را قبل از باز کردن شل، درون سشن PowerShell بارگذاری کنیم. PowerShell از چندین نوع پروفایل پشتیبانی میکند و توسط متغیر خودکار PROFILE$ میتوانیم لیست مسیرهای پروفایلها را مشاهده کنیم:
PS /> $PROFILE | Get-Member -Type NoteProperty | Select-Object Name, Definitionbject Name, Definition Name Definition ---- ---------- AllUsersAllHosts string AllUsersAllHosts=/usr/local/microsoft/powershell/7/… AllUsersCurrentHost string AllUsersCurrentHost=/usr/local/microsoft/powershell… CurrentUserAllHosts string CurrentUserAllHosts=/Users/sirwanafifi/.config/powe… CurrentUserCurrentHost string CurrentUserCurrentHost=/Users/sirwanafifi/.config/p…
$SlackProjectPath = "/Users/sirwanafifi/Desktop/ps_cmdlet_with_csharp/bin/Debug/net7.0/ps_cmdlet_with_csharp.dll" Import-Module $SlackProjectPath
PS /> Get-Command -Module ps_cmdlet_with_csharp CommandType Name Version Source ----------- ---- ------- ---- Cmdlet Push-SlackMessage 1.0.0.0 ps_…
اشتراکها
#C پنجمین زبان محبوب GitHub
نگاهی به روند تکاملی نحوهی تعریف خواص از C# 1.0 تا C# 9.0
در C# 1.0 برای تعریف خواص، نیاز به نوشتن مقدار زیادی کد بود:
در اینجا تعریف backing fieldها (مانند public string _firstName) و استفادهی دستی از آنها الزامی بود.
در C# 2.0 از لحاظ ساده سازی این تعاریف، اتفاق خاصی رخنداد. فقط امکان تعریف سطوح دسترسی مانند private بر روی getterها و setterها میسر شد:
در C# 6.0، امکان حذف private setterها از تعریف یک خاصیت میسر شد. یعنی مثال زیر را
به این نحو سادهتر و واضحتر نیز میتوان نوشت:
بهعلاوه در همین زمان بود که امکان مقدار دهی اولیهی خواص نیز در همان سطر تعریف آنها ممکن شد:
پیش از این برای مقدار دهی اولیهی خواص در همان کلاسی که آنها را تعریف میکند، میبایستی از طریق مقدار دهی آنها در سازندهی کلاس اقدام میشد.
همچنین در C# 6.0 با معرفی expression bodied members که بر روی خواص نیز قابل اعمال است، امکان تعریف خواص readonly محاسبه شدهی بر اساس مقدار سایر خواص نیز میسر شد:
و در C# 9.0، با معرفی واژهی کلیدی init، امکان تعریف سادهتر خواص immutable ممکن شدهاست که در مطلب جاری به آن خواهیم پرداختیم.
روش غیرقابل مقدار دهی کردن خواص، در نگارشها پیش از C# 9.0
در بسیاری از موارد میخواهیم که خاصیتی از یک کلاس مدل، در خارج از آن قابل تغییر نباشد (مانند خواص شیءای که به محتوای فایل config ثابت برنامه اشاره میکند). راه حل فعلی آن تا پیش از C# 9.0 به صورت زیر است:
که در این حالت دیگر نمیتوان مقدار خاصیت Name را در خارج از کلاس User مقدار دهی کرد:
وبا اینکار خطای کامپایلر زیر را دریافت میکنیم:
در این تعریف باتوجه به وجود private set، برای مقداردهی خاصیت Name میتوان از یکی از دو روش زیر در داخل کلاس User استفاده کرد:
- تنظیم مقدار خاصیت Name در سازندهی کلاس
- و یا تنظیم این مقدار در یک متد ثالث دیگر مانند SetName
در هر دو حالت، از مقدار دهی مستقیم خاصیت Name توسط Object Initializer (یا همان روش متداول new User { Name = "some name"}) محروم میشویم. همچنین در ادامه شاید نیاز باشد که این خاصیت پس از مقدار دهی اولیه، دیگر قابل تغییر نباشد؛ یا به عبارتی immutable شود. در مثال فوق هنوز هم امکان تغییر مقدار خاصیت Name درون کلاس User، با فراخوانیهای بعدی متد SetName، وجود دارد.
معرفی خواص Init-Only در C# 9.0
برای رفع دو مشکل یاد شده (امکان تنظیم مقدار خاصیتها با همان روش متداول object initializer و همچنین غیرقابل تغییر شدن آنها)، اکنون در C# 9.0 میتوان بجای private set از واژهی کلیدی init استفاده کرد:
در اینجا تنها تغییر صورت گرفته، استفاده از واژهی کلیدی init، در حین تعریف خاصیت Name است. به این ترتیب به دو مزیت زیر دسترسی پیدا میکنیم:
الف) امکان مقدار دهی خاصیت Name، در خارج بدنهی کلاس User و توسط روش متداول کار با object initializerها هنوز هم وجود دارد و در این حالت الزامی به تعریف یک سازنده و یا متد خاصی درون کلاس User برای مقدار دهی آن نیست:
ب) پس از اولین بار مقدار دهی این خاصیت init-only، دیگر نمیتوان مقدار آنرا تغییر داد:
این نکته در مورد متدهای داخل کلاس User هم صدق میکند:
میتوان یک خاصیت init-only را برای بار اول، در سازندهی همان کلاس نیز مقدار دهی کرد؛ اما مقدار دهی ثانویهی آن در سایر متدهای داخل کلاس User نیز به خطای زمان کامپایل یاد شده، ختم میشود و مجاز نیست.
روش تعریف immutable properties در نگارشهای پیشین #C
با استفاده از واژهی readonly در نگارشهای قبلی #C نیز میتوان به صورت زیر، یک خاصیت را به صورت غیرقابل تغییر یا immutable در آورد:
هرچند این روش کار میکند اما دیگر همانند init-only properties نمیتوان از طریق object initializers خاصیت Name را مقدار دهی کرد و این مقدار دهی حتما باید از طریق سازندهی کلاس باشد. همچنین ایجاد یک اصطلاحا backing filed هم برای آن، کدها را طولانیتر میکند.
یک نکته: امکان استفادهی از فیلدهای readonly با خواص init-only هم وجود دارد؛ از این جهت که این نوع خواص تنها در زمان نمونه سازی اولیهی شیء، اجرا و مقدار دهی میشوند، با مفهوم readonly، سازگاری دارند:
در C# 1.0 برای تعریف خواص، نیاز به نوشتن مقدار زیادی کد بود:
public class Person { public string _firstName; public string FirstName { get { return _firstName; } set { _firstName = value; } } }
در C# 2.0 از لحاظ ساده سازی این تعاریف، اتفاق خاصی رخنداد. فقط امکان تعریف سطوح دسترسی مانند private بر روی getterها و setterها میسر شد:
public string _firstName; public string FirstName { get { return _firstName; } private set { _firstName = value; } }
در C# 3.0 بود که با ارائهی auto-implemented properties، نحوهی تعریف خواص، بسیار ساده شد و دیگر نیازی به تعریف backing fieldها نبود؛ چون کامپایلر به صورت خودکار آنها را در پشت صحنه ایجاد میکرد/میکند:
public class Person { public string FirstName { get; set; } }
در C# 6.0، امکان حذف private setterها از تعریف یک خاصیت میسر شد. یعنی مثال زیر را
public class User { public string Name { get; private set; } }
public class User { public string Name { get; } }
public class Foo { public string FirstName { get; set; } = "Initial Value"; }
همچنین در C# 6.0 با معرفی expression bodied members که بر روی خواص نیز قابل اعمال است، امکان تعریف خواص readonly محاسبه شدهی بر اساس مقدار سایر خواص نیز میسر شد:
public class Foo { public DateTime DateOfBirth { get; set; } public int Age => DateTime.Now.Year - DateOfBirth.Year; }
و در C# 9.0، با معرفی واژهی کلیدی init، امکان تعریف سادهتر خواص immutable ممکن شدهاست که در مطلب جاری به آن خواهیم پرداختیم.
روش غیرقابل مقدار دهی کردن خواص، در نگارشها پیش از C# 9.0
در بسیاری از موارد میخواهیم که خاصیتی از یک کلاس مدل، در خارج از آن قابل تغییر نباشد (مانند خواص شیءای که به محتوای فایل config ثابت برنامه اشاره میکند). راه حل فعلی آن تا پیش از C# 9.0 به صورت زیر است:
public class User { public string Name { get; private set; } }
var user = new User { Name = "User 1" // Compile Error };
The property or indexer 'User.Name' cannot be used in this context because the set accessor is inaccessible [CS9Features]csharp(CS0272)
- تنظیم مقدار خاصیت Name در سازندهی کلاس
- و یا تنظیم این مقدار در یک متد ثالث دیگر مانند SetName
public class User { public User(string name) { this.Name = name; } public void SetName(string name) { this.Name = name; } public string Name { get; private set; } }
معرفی خواص Init-Only در C# 9.0
برای رفع دو مشکل یاد شده (امکان تنظیم مقدار خاصیتها با همان روش متداول object initializer و همچنین غیرقابل تغییر شدن آنها)، اکنون در C# 9.0 میتوان بجای private set از واژهی کلیدی init استفاده کرد:
public class User { public string Name { get; init; } }
الف) امکان مقدار دهی خاصیت Name، در خارج بدنهی کلاس User و توسط روش متداول کار با object initializerها هنوز هم وجود دارد و در این حالت الزامی به تعریف یک سازنده و یا متد خاصی درون کلاس User برای مقدار دهی آن نیست:
var user = new User { Name = "User 1" };
// Compile Time Error // Init-only property or indexer 'User.Name' can only be assigned in an object initializer, // or on 'this' or 'base' in an instance constructor or an 'init' accessor. [CS9Features]csharp(CS8852) user.Name = "Test";
public class User { public string Name { get; init; } public User(string name) { this.Name = name; // Works fine } public void SetName(string name) { this.Name = name; // Compile Time Error } }
روش تعریف immutable properties در نگارشهای پیشین #C
با استفاده از واژهی readonly در نگارشهای قبلی #C نیز میتوان به صورت زیر، یک خاصیت را به صورت غیرقابل تغییر یا immutable در آورد:
public class Product { public Product(string name) { _name = name; } private readonly string _name; public string Name => _name; }
یک نکته: امکان استفادهی از فیلدهای readonly با خواص init-only هم وجود دارد؛ از این جهت که این نوع خواص تنها در زمان نمونه سازی اولیهی شیء، اجرا و مقدار دهی میشوند، با مفهوم readonly، سازگاری دارند:
public class Person { private readonly string _name; public string Name { get => _name; init => _name = value; } }
نظرات مطالب
هزینه استفاده از دات نت فریم ورک چقدر است؟
- نسخه express منهای بحث افزونه پذیری و مواردی که ذکر شد، چیزی کمتر از نسخهی ultimate ندارد. توسعه دهندهی حرفهای هم که نمیدونه مثلا بجای MSTest میتونه از NUnit استفاده کنه، خوب کمی این واژهی حرفهای برازندهی اون نیست.
- اون مورد کامپایل دستی هم به این دلیل ذکر شد که کمی بیشتر با امکانات موجود آشنا بشیم. کمی شناخت بیشتری از زیر ساختها پیدا کنیم.
- در مونو که عرض کردم دیگری پروژهی شرکت ناول وجود ندارد. الان شده زاماریان. در همان زمان هم جالب است بدونید مایکروسافت کمکهای مادی زیادی به ناول کرد که لینوکسیها خیلی به این قضیه مشکوک شده بودند که چرا. در مورد برنامههای پیاده سازی شده با آن هم لطفا به لیستی که در سایت آنها هست مراجعه کنید. ضرورتی به تکرار آنها اینجا نیست.
- بله میشود در محیط تجاری از آنها استفاده کرد و خیلیها اینکار رو میکنند.
- اینکه بقیه کم اطلاع هستند خوب میشود اطلاع رسانی کرد. به همین دلیل این مطلب نوشته شده. هدف دیگری در کار نبود.
- اینکه زبانهای دیگه به این حد نرسیدن مشکل طرفداران آنها هست. بروند کتاب چاپ کنند، زحمت بکشند، تلاش کنند. مثلا فکر میکنید سرپا نگه داشتن همین بلاگ کار سادهای است؟ برای نمونه مطلبی رو که در مورد تبدیل html to pdf چند روز قبل منتشر کردم یک هفته کار برده بود تا نحوهی اعمال فونت فارسی رو به اون بتونم تکمیل کنم.
- اون مورد کامپایل دستی هم به این دلیل ذکر شد که کمی بیشتر با امکانات موجود آشنا بشیم. کمی شناخت بیشتری از زیر ساختها پیدا کنیم.
- در مونو که عرض کردم دیگری پروژهی شرکت ناول وجود ندارد. الان شده زاماریان. در همان زمان هم جالب است بدونید مایکروسافت کمکهای مادی زیادی به ناول کرد که لینوکسیها خیلی به این قضیه مشکوک شده بودند که چرا. در مورد برنامههای پیاده سازی شده با آن هم لطفا به لیستی که در سایت آنها هست مراجعه کنید. ضرورتی به تکرار آنها اینجا نیست.
- بله میشود در محیط تجاری از آنها استفاده کرد و خیلیها اینکار رو میکنند.
- اینکه بقیه کم اطلاع هستند خوب میشود اطلاع رسانی کرد. به همین دلیل این مطلب نوشته شده. هدف دیگری در کار نبود.
- اینکه زبانهای دیگه به این حد نرسیدن مشکل طرفداران آنها هست. بروند کتاب چاپ کنند، زحمت بکشند، تلاش کنند. مثلا فکر میکنید سرپا نگه داشتن همین بلاگ کار سادهای است؟ برای نمونه مطلبی رو که در مورد تبدیل html to pdf چند روز قبل منتشر کردم یک هفته کار برده بود تا نحوهی اعمال فونت فارسی رو به اون بتونم تکمیل کنم.
نظرات مطالب
هزینه استفاده از دات نت فریم ورک چقدر است؟
- نسخه express منهای بحث افزونه پذیری و مواردی که ذکر شد، چیزی کمتر از نسخهی ultimate ندارد. توسعه دهندهی حرفهای هم که نمیدونه مثلا بجای MSTest میتونه از NUnit استفاده کنه، خوب کمی این واژهی حرفهای برازندهی اون نیست.
- اون مورد کامپایل دستی هم به این دلیل ذکر شد که کمی بیشتر با امکانات موجود آشنا بشیم. کمی شناخت بیشتری از زیر ساختها پیدا کنیم.
- در مونو که عرض کردم دیگری پروژهی شرکت ناول وجود ندارد. الان شده زاماریان. در همان زمان هم جالب است بدونید مایکروسافت کمکهای مادی زیادی به ناول کرد که لینوکسیها خیلی به این قضیه مشکوک شده بودند که چرا. در مورد برنامههای پیاده سازی شده با آن هم لطفا به لیستی که در سایت آنها هست مراجعه کنید. ضرورتی به تکرار آنها اینجا نیست.
- بله میشود در محیط تجاری از آنها استفاده کرد و خیلیها اینکار رو میکنند.
- اینکه بقیه کم اطلاع هستند خوب میشود اطلاع رسانی کرد. به همین دلیل این مطلب نوشته شده. هدف دیگری در کار نبود.
- اینکه زبانهای دیگه به این حد نرسیدن مشکل طرفداران آنها هست. بروند کتاب چاپ کنند، زحمت بکشند، تلاش کنند. مثلا فکر میکنید سرپا نگه داشتن همین بلاگ کار سادهای است؟ برای نمونه مطلبی رو که در مورد تبدیل html to pdf چند روز قبل منتشر کردم یک هفته کار برده بود تا نحوهی اعمال فونت فارسی رو به اون بتونم تکمیل کنم.
- اون مورد کامپایل دستی هم به این دلیل ذکر شد که کمی بیشتر با امکانات موجود آشنا بشیم. کمی شناخت بیشتری از زیر ساختها پیدا کنیم.
- در مونو که عرض کردم دیگری پروژهی شرکت ناول وجود ندارد. الان شده زاماریان. در همان زمان هم جالب است بدونید مایکروسافت کمکهای مادی زیادی به ناول کرد که لینوکسیها خیلی به این قضیه مشکوک شده بودند که چرا. در مورد برنامههای پیاده سازی شده با آن هم لطفا به لیستی که در سایت آنها هست مراجعه کنید. ضرورتی به تکرار آنها اینجا نیست.
- بله میشود در محیط تجاری از آنها استفاده کرد و خیلیها اینکار رو میکنند.
- اینکه بقیه کم اطلاع هستند خوب میشود اطلاع رسانی کرد. به همین دلیل این مطلب نوشته شده. هدف دیگری در کار نبود.
- اینکه زبانهای دیگه به این حد نرسیدن مشکل طرفداران آنها هست. بروند کتاب چاپ کنند، زحمت بکشند، تلاش کنند. مثلا فکر میکنید سرپا نگه داشتن همین بلاگ کار سادهای است؟ برای نمونه مطلبی رو که در مورد تبدیل html to pdf چند روز قبل منتشر کردم یک هفته کار برده بود تا نحوهی اعمال فونت فارسی رو به اون بتونم تکمیل کنم.
اشتراکها
تصورات غلط در مورد دورکاری
Have you ever discussed remote work with someone who has never worked remotely? How did it go? If they were like most people, it probably didn’t go all that well. It can be difficult for people to understand how someone could work from home, be productive, and end up being a normal human being at the end of the day.