C#学习日记2

1.C#委托
解析:所有的委托都派生自System.Delegate类。
[1]声明委托
假设有一个委托,如下所示:

public delegate int MyDelegate (string s);

上面的委托可被用于引用任何一个带有一个单一的string参数的方法,并返回一个int类型变量。
声明委托的语法,如下所示:

delegate <return type> <delegate-name> <parameter list>

[2]实例化委托
一旦声明了委托类型,委托对象必须使用new关键字来创建,且与一个特定的方法有关。当创建委托时,传递到new语句的参数就像方法调用一样书写,但是不带有参数。如下所示:

public delegate void printString(string s);
...
printString ps1 = new printString(WriteToScreen);
printString ps2 = new printString(WriteToFile);

下面的实例演示了委托的声明、实例化和使用,该委托可用于引用带有一个整型参数的方法,并返回一个整型值。

using System;

delegate int NumberChanger(int n);
namespace DelegateAppl
{
   class TestDelegate
   {
      static int num = 10;
      public static int AddNum(int p)
      {
         num += p;
         return num;
      }

      public static int MultNum(int q)
      {
         num *= q;
         return num;
      }
      public static int getNum()
      {
         return num;
      }

      static void Main(string[] args)
      {
         // 创建委托实例
         NumberChanger nc1 = new NumberChanger(AddNum);
         NumberChanger nc2 = new NumberChanger(MultNum);
         // 使用委托对象调用方法
         nc1(25);
         Console.WriteLine("Value of Num: {0}", getNum());
         nc2(5);
         Console.WriteLine("Value of Num: {0}", getNum());
         Console.ReadKey();
      }
   }
}

编译和执行上述代码,输出结果如下所示:

Value of Num: 35
Value of Num: 175

[3]委托的多播
委托对象可使用"+“运算符进行合并。一个合并委托调用它所合并的两个委托。只有相同类型的委托可被合并。”-"运算符可用于从合并的委托中移除组件委托。使用委托的这个有用的特点,您可以创建一个委托被调用时要调用的方法的调用列表。这被称为委托的多播,也叫组播。如下所示:

using System;

delegate int NumberChanger(int n);
namespace DelegateAppl
{
   class TestDelegate
   {
      static int num = 10;
      public static int AddNum(int p)
      {
         num += p;
         return num;
      }

      public static int MultNum(int q)
      {
         num *= q;
         return num;
      }
      public static int getNum()
      {
         return num;
      }

      static void Main(string[] args)
      {
         // 创建委托实例
         NumberChanger nc;
         NumberChanger nc1 = new NumberChanger(AddNum);
         NumberChanger nc2 = new NumberChanger(MultNum);
         nc = nc1;
         nc += nc2;
         // 调用多播
         nc(5);
         Console.WriteLine("Value of Num: {0}", getNum());
         Console.ReadKey();
      }
   }
}

编译和执行代码,结果如下所示:

Value of Num: 75

[4]委托的用途
下面的实例演示了委托的用法。委托printString可用于引用带有一个字符串作为输入的方法,并不返回任何东西。使用这个委托来调用两个方法,第一个把字符串打印到控制台,第二个把字符串打印到文件:

using System;
using System.IO;

namespace DelegateAppl
{
   class PrintString
   {
      static FileStream fs;
      static StreamWriter sw;
      // 委托声明
      public delegate void printString(string s);

      // 该方法打印到控制台
      public static void WriteToScreen(string str)
      {
         Console.WriteLine("The String is: {0}", str);
      }
      // 该方法打印到文件
      public static void WriteToFile(string s)
      {
         fs = new FileStream("c:\\message.txt",
         FileMode.Append, FileAccess.Write);
         sw = new StreamWriter(fs);
         sw.WriteLine(s);
         sw.Flush();
         sw.Close();
         fs.Close();
      }
      // 该方法把委托作为参数,并使用它调用方法
      public static void sendString(printString ps)
      {
         ps("Hello World");
      }
      static void Main(string[] args)
      {
         printString ps1 = new printString(WriteToScreen);
         printString ps2 = new printString(WriteToFile);
         sendString(ps1);
         sendString(ps2);
         Console.ReadKey();
      }
   }
}

编译和执行代码,如下所示:

The String is: Hello World

说明:委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数的做法,可以避免在程序中大量使用If-Else(Switch)语句,同时使得程序具有更好的可扩展性。

2.C#事件
解析:事件基本上说是一个用户操作,如按键、点击、鼠标移动等等,或者是一些提示信息,如系统生成的通知。应用程序需要在事件发生时响应事件。C#中使用事件机制实现线程间的通信。
[1]通过事件使用委托
事件在类中声明且生成,且通过使用同一个类或其它类中的委托与事件处理程序关联。包含事件的类用于发布事件,这被称为发布器[publisher]类。其它接受该事件的类被称为订阅器[subscriber]类。事件使用发布-订阅[publisher-subscriber]模型。

  • 发布器[publisher]:一个包含事件和委托定义的对象。事件和委托之间的联系也定义在这个对象中。发布器类的对象调用这个事件,并通知其他的对象。
  • 订阅器[subscriber]:一个接受事件并提供事件处理程序的对象。在发布器类中的委托调用订阅器类中的方法[事件处理程序]。

[2]声明事件
在类的内部声明事件,首先必须声明该事件的委托类型。如下所示:

public delegate void BoilerLogHandler(string status);

然后声明事件本身,使用event关键字:

public event BoilerLogHandler BoilerEventLog;

说明:上面的代码定义了一个名为BoilerLogHandler的委托和一个名为BoilerEventLog的事件,该事件在生成的时候会调用委托。

3.事件实例1

using System;

namespace SimpleEvent
{
    /***********发布器类***********/
    public class EventTest
    {
        private int value;

        public delegate void NumManipulationHandler();


        public event NumManipulationHandler ChangeNum;

        protected virtual void OnNumChanged()
        {
            if (ChangeNum != null)
            {
                ChangeNum(); /* 事件被触发 */
            }
            else
            {
                Console.WriteLine("event not fire");
                Console.ReadKey(); /* 回车继续 */
            }
        }


        public EventTest()
        {
            int n = 5;
            SetValue(n);
        }


        public void SetValue(int n)
        {
            if (value != n)
            {
                value = n;
                OnNumChanged();
            }
        }
    }


    /***********订阅器类***********/

    public class subscribEvent
    {
        public void printf()
        {
            Console.WriteLine("event fire");
            Console.ReadKey(); /* 回车继续 */
        }
    }

    /***********触发***********/
    public class MainClass
    {
        public static void Main()
        {
            EventTest e = new EventTest(); /* 实例化对象,第一次没有触发事件 */
            subscribEvent v = new subscribEvent(); /* 实例化对象 */
            e.ChangeNum += new EventTest.NumManipulationHandler(v.printf); /* 注册 */
            e.SetValue(7);
            e.SetValue(11);
        }
    }
}

编译和执行代码,结果输出如下所示:

event not fire
event fire
event fire

4.事件实例2
本实例提供一个简单的用于热水锅炉系统故障排除的应用程序。当维修工程师检查锅炉时,锅炉的温度和压力会随着维修工程师的备注自动记录到日志文件中。如下所示:

using System;
using System.IO;

namespace BoilerEventAppl
{
    // boiler 类
    class Boiler
    {
        private int temp;
        private int pressure;

        public Boiler(int t, int p)
        {
            temp = t;
            pressure = p;
        }

        public int getTemp()
        {
            return temp;
        }

        public int getPressure()
        {
            return pressure;
        }
    }

    // 事件发布器
    class DelegateBoilerEvent
    {
        public delegate void BoilerLogHandler(string status);

        // 基于上面的委托定义事件
        public event BoilerLogHandler BoilerEventLog;

        public void LogProcess()
        {
            string remarks = "O. K";
            Boiler b = new Boiler(100, 12);
            int t = b.getTemp();
            int p = b.getPressure();
            if (t > 150 || t < 80 || p < 12 || p > 15)
            {
                remarks = "Need Maintenance";
            }

            OnBoilerEventLog("Logging Info:\n");
            OnBoilerEventLog("Temparature " + t + "\nPressure: " + p);
            OnBoilerEventLog("\nMessage: " + remarks);
        }

        protected void OnBoilerEventLog(string message)
        {
            if (BoilerEventLog != null)
            {
                BoilerEventLog(message);
            }
        }
    }

    // 该类保留写入日志文件的条款
    class BoilerInfoLogger
    {
        FileStream fs;
        StreamWriter sw;

        public BoilerInfoLogger(string filename)
        {
            fs = new FileStream(filename, FileMode.Append, FileAccess.Write);
            sw = new StreamWriter(fs);
        }

        public void Logger(string info)
        {
            sw.WriteLine(info);
        }

        public void Close()
        {
            sw.Close();
            fs.Close();
        }
    }

    // 事件订阅器
    public class RecordBoilerInfo
    {
        static void Logger(string info)
        {
            Console.WriteLine(info);
        } //end of Logger

        static void Main(string[] args)
        {
            BoilerInfoLogger filelog = new BoilerInfoLogger("e:\\boiler.txt");
            DelegateBoilerEvent boilerEvent = new DelegateBoilerEvent();
            boilerEvent.BoilerEventLog += new
                DelegateBoilerEvent.BoilerLogHandler(Logger);
            boilerEvent.BoilerEventLog += new
                DelegateBoilerEvent.BoilerLogHandler(filelog.Logger);
            boilerEvent.LogProcess();
            Console.ReadLine();
            filelog.Close();
        } //end of main
    } //end of RecordBoilerInfo
}

编译和执行代码,结果输出如下所示:

Logging info:
Temperature 100
Pressure 12
Message: O. K

5.System.Linq
解析:System.Linq命名空间提供支持使用语言集成查询[LINQ]进行查询的类和接口。

6.WPF体系结构
解析:WPF使用多层体系结构。在顶层,应用程序与完全由托管C#代码编写的一组高层服务进行交互。至于将.NET对象转换为Direct3D纹理和三角形的实际工作,是在后台由一个名为milcore.dll的低级非托管组件完成的。milcore.dll是使用非托管代码实现的,因为它需要和Direct3D紧密集成,并且它对性能极其敏感。
[1]PresentationFramework.dll:包含WPF顶层的类型,包含那些表示窗口、面板以及其它类型控件的类型。它还实现了高层编程抽象,比如样式。开发人员直接使用的大部分类都来自这个程序集。
[2]PresentationCore.dll:包含了基础类型,比如UIElementVisual类,所有形状类和控件类都继承自这两个类。如果不需要窗口和控件抽象层的全部特征,可使用这一层,而且仍能利用WPF的渲染引擎。
[3]WindowsBase.dll:包含了更多基本要素,浙西要素具有在WPF之外重用的潜能,比如DispatcherObject类和DependencyObject类,这两个类引入了依赖项属性。
[4]milcore.dll:WPF渲染系统的核心,也是媒体集成层[MIL]的基础。其合成引擎将可视化元素转换为Direct3D所期望的三角形和纹理。尽管将milcore.dll视为WPF的一部分,但它也是Windows Vista和Windows 7的核心系统组件之一。实际上,桌面窗口管理器[DWM]使用milcore.dll渲染桌面。
[5]WindowsCodecs.dll:一套提供图像支持的低级API,比如处理、显示以及缩放位图和JPEG图像。
[6]Direct3D:一套低级API,WPF应用程序中的所有图形都由它进行渲染。
[7]User32:用于决定哪些程序实际占有桌面的哪一部分,所以它仍被包含在WPF中,但不再负责渲染通用控件。

7.WPF类层次结构
解析:
[1]System.Threading.DispatcherObject类
WPF应用程序使用为人熟知的单线程亲和[STA]模型,这意味着整个用户界面由单个线程拥有。从另一个线程与用户界面元素进行交互是不安全的。为方便使用此模型,每个WPF应用程序由协调消息[键盘输入、鼠标移动乃至框架处理,比如布局]的调度程序管理。通过继承自DispatcherObject类,用户界面中的每个元素都可以检查代码是否在正确的线程上运行,并能通过访问调度程序为用户界面线程封送代码。
[2]System.Windows.DependencyObject类
在WPF中,主要通过属性与屏幕上的元素进行交互。在早期设计阶段,WPF的设计者决定创建一个更加强大的属性模型,该模型支持许多特性,比如更改通知、默认值继承以及减少属性存储空间。最终结果是依赖项属性特性。通过继承自DependencyObject类,WPF类可获得对依赖项属性的支持。
[3]System.Windows.Media.Visual类
在WPF窗口中显示的每个元素本质上都是Visual对象。可将Visual类视为绘图对象,其中封装了绘图指令、如何执行绘图的附加细节[比如剪裁、透明度以及变换设置]以及基本功能[比如命中测试]。Visual类还在托管的WPF类和渲染桌面的milcore.dll程序集之间提供了链接。任何继承自Visual的类都能在窗口上显示出来。如果更愿意使用轻量级的API创建用户界面,而不想使用WPF的高级框架特征,可直接对Visual对象进行编程。
[4]System.Windows.UIElement类
UIElement类增加了对WPF本质特征的支持,比如布局、输入、焦点和实践。在该类中,原始的鼠标单击和按键操作被转换为更有用的事件,比如MouseEnter事件。与属性类似,WPF实现了增强的称为路由事件的事件路由系统。
[5]System.Windows.FrameworkElement类
FrameworkElement类是WPF核心继承树中的最后一站。该类实现了一些全部由UIElement类定义的成员。比如,UIElement类为WPF布局系统设置了基础,但FrameworkElement类提供了支持它的重要属性[比如,HorizontalAlignment和Margin属性]。UIElement类还添加了对数据绑定、动画以及样式等核心特性的支持。
[6]System.Windows.Shapes.Shape类
基本的形状类[比如Rectangle类、Polygon类、Ellipse类、Line类以及Path类]都继承自该类。可将这些形状类与更传统的Windows小组件[比如按钮和文本框]结合使用。
[7]System.Windows.Controls.Control类
控件是可与用户进行交互的元素。控件显然包括TextBox类、Button类和ListBox类等。Control类为设置字体以及前景色与背景色提供了附加属性。但最令人感兴趣的细节是模板支持,通过模板支持,可使用自定义风格的绘图替换控件的标准外观。
[8]System.Windows.Controls.ContentControl类
ContentControl类是所有具有单一内容的控件的基类,包括简单的标签乃至窗口的所有内容。该模型给人印象最深刻的部分是:控件中的单一内容可以是普通字符串乃至具有其它形状和控件组合的布局面板。
[9]System.Windows.Controls.ItemsControl类
ItemsControl类是所有显示选项集合的控件的基类,比如ListBox和TreeView控件。列表控件十分灵活,比如适用ItemsControl类的内置特征,可将简单的ListBox控件变换成单选按钮列表、复选框控件列表、平铺的图像或是所选择的完全不同的元素的组合。实际上,WPF中的菜单、工具栏以及状态栏都是特定的列表,并且实现它们的类都继承自ItemsControl类。
[10]System.Windows.Controls.Panel类
Panel类是所有布局容器的基类,布局容器是可包含一个或多个子元素、并按特定规则对子元素进行排列的元素。这些容器是WPF布局系统的基础,要以最富有吸引力、最灵活的方式安排内容,使用这些容器是关键所在。

8.Xamarin.Forms框架
解析:Xamarin.Forms框架让开发人员能够快速创建跨平台用户界面。它为用户界面提供自己的抽象,用户界面可使用iOS、Android、Windows或WindowsPhone上的本机控件呈现。这意味着应用程序可以共享大部分用户界面代码,同时保留目标平台的本机外观。

9.System.ServiceModel
解析:Provides classes related to the service model.

10.NuGet
解析:Nuget是一个.NET平台下的开源的项目,它是Visual Studio的扩展。在使用Visual Studio开发基于.NET Framework的应用时,Nuget能把在项目中添加、移除和更新引用的工作变得更加快捷方便。

11.StackPanel布局
解析:StackPanel可以把内部元素在纵向或横向上紧凑排列,形成栈式布局。如下所示:

<Grid>
    <GroupBox Header="请选择没有错别字的成语"  BorderBrush="Black" Margin="5">
        <StackPanel Margin="5" Height="271">
            <CheckBox Content="A.迫不及待" />
            <CheckBox Content="B.首屈一指" />
            <CheckBox Content="C.陈词滥调" />
            <CheckBox Content="D.不可理喻" />
            <StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
                <Button Content="清空" Width="60" Margin="5" />
                <Button Content="确定" Width="60" Margin="5" />
            </StackPanel>
        </StackPanel>
    </GroupBox>
</Grid>

12.WPF内建面板
解析:Canvas、StackPanel、WrapPanel、DockPanel和Grid是WPF中主要的5种内建面板,这些面板类都位于System.Windows.Controls命名空间下。

13.UpdateSourceTrigger属性
解析:如果把它设置为UpdateSourceTrigger.PropertyChanged,那么Target被关联的属性只要一改变,就立刻传回给Source。

14.C#中double与Double的区别
解析:double是一个数据类型,Double是一个类,两者可以转换。

15.App.config
解析:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
    </startup>
</configuration>

说明:C#获取App.Config中的配置项内容主要通过CinfigurationManager类进行。

16.object sender
解析:触发事件的控件。

17.ProgressBar控件
解析:
[1]FontFamily:控件中显示文本的字体。
[2]FontSize:控件中显示的字体的大小。
[3]Foreground:控件中显示的文本的前景色。
[4]Text:显示的文本的内容。
[5]TextWrapping:控件中显示的文本的换行方式。
[6]NoWrap:不自动换行,超出的部分被截断。
[7]Wrap:自动换行,文本长度超出控件宽度时自动换行。
[8]Visibility:值为True时文本可见,值为False时文本不可见。

18.可空数据类型
解析:
[1]在不可null类型后加?就可以为null。比如,int?,DateTime?。
[2]可以把int赋值给int?,但不可以把int?赋值给int。
[3]把int?赋值给int需要强制类型转换。

19.TabControl控件
解析:TabControl控件可以支持在一个控件里面放置多个选项卡,每个选项卡又可以放置多个控件。

20.DockPanel控件
解析:DockPanel控件提供了附加属性Dock。这是一个Dock枚举类型,如下所示:
[1]Left:位于DockPanel左侧的子元素。
[2]Top:位于DockPanel的顶部的子元素。
[3]Right:位于DockPanel右侧的子元素。
[4]Bottom:位于DockPanel底部的子元素。

<DockPanel>
        <Button x:Name="button" Content="Button" DockPanel.Dock="Top" />
        <Button x:Name="button1" Content="Button" DockPanel.Dock="Bottom" />
        <Button x:Name="button2" Content="button" DockPanel.Dock="Left"/>
        <Button Name="btn1" Content="button2" DockPanel.Dock="Right"/>
        <Button x:Name="button3" Content="Button" />
</DockPanel>

21.Grid跨行和跨列
解析:
[1]跨行:Grid.RowSpan
[2]跨列:Grid.ColumnSpan

22.MouseUp事件
解析:MouseUp事件使用的是一个名为MouseButtonEventHandler的委托,它有两个参数,sender[发生事件的控件],MouseButtonEventArgs[一些有用的信息,比如通过它获取了鼠标的位置]。

23.WPF的Window类属性
解析:
[1]Icon:允许定义窗口的图标。
[2]ResizeMode:控制最终用户是否以及如何调整窗口大小。
[3]SizeToContent:决定Window是否应调整自身大小以自动适应其内容。
[4]Topmost:窗口将保持在其它窗口之上。
[5]WindowStartupLocation:控制窗口的初始位置。
[6]WindowState:控制初始窗口状态,它可以是Normal,Maximized或Minimized。

24.StartupUri="MainWindow.xaml"
解析:StartupUri属性指定了当应用程序启动时应该被加载的Window或Page。

25.System.Uri类
解析:System.Uri类用于处理Uri地址信息,常用到它的地方有,相对Uri地址转绝对Uri地址,获取Uri的某部分信息等。
属性如下所示:
[1]AbsolutePath:获取URI的绝对路径。
[2]AbsoluteUri:获取绝对URI。
[3]Authority:获取服务器的域名系统[DNS]主机名或IP地址和端口号。
[4]DnsSafeHost:获得可安全用于DNS解析的未转义主机名。
[5]Fragment:获取转义URI片段。
[6]Host:获取此实例的主机部分。
[7]HostNameType:获取URI中指定的主机名的类型。
[8]IsAbsoluteUri:获取一个值,该值指示Uri实例是否为绝对URI。
[9]IsDefaultPort:获取一个值,该值指示URI的端口值是否为此方案的默认值。
[10]IsFile:获取一个值,该值指示指定的Uri是否为文件URI。
[11]IsLoopback:获取一个值,该值指示指定的Uri是否引用了本地主机。
[12]IsUnc:获取一个值,该值指示指定的Uri是否为统一命名约定[UNC]路径。
[13]LocalPath:获取文件名的本地操作系统表示形式。
[14]OriginalString:获取传递给Uri构造函数的原始URI字符串。
[15]PathAndQuery:获取用问号[?]分隔的AbsolutePath和Query属性。
[16]Port:获取此URI的端口号。
[17]Query:获取指定URI中包括的任何查询信息。
[18]Scheme:获取此URI的方案名称。
[19]Segments:获取包含构成指定URI的路径段的数组。
[20]UserEscaped:指示URI字符串在创建Uri实例之前已被完全转义。
[21]UserInfo:获取用户名、密码或其他与指定URI关联的特定于用户的信息。
方法如下所示:
[1]CheckHostName:确定指定的主机名是否为有效的DNS名称。
[2]CheckSchemeName:确定指定的方案名是否有效。
[3]Compare:使用指定的比较规则比较两个URI的指定部分。
[4]EscapeDataString:将字符串转换为它的转义表示形式。
[5]EscapeUriString:将URI字符串转换为它的转义表示形式。
[6]FromHex:获取十六进制数字的十进制值。
[7]GetComponents:使用特殊字符的指定转义,获取当前实例的指定部分。
[8]GetLeftPart:获取Uri实例的指定部分。
[9]GetObjectData:返回序列化当前实例所需的数据。
[10]HexEscape:将指定的字符转换它的等效十六进制字符。
[11]HexUnescape:将字符的指定十六进制表示形式转换为字符。
[12]IsBaseOf:确定当前的Uri实例是否为指定Uri实例的基。
[13]IsHexDigit:确定指定的字符是否为有效的十六进制数字。
[14]IsHexEncoding:确定字符串中的一个字符是否为十六进制编码。
[15]IsWellFormedOriginalString:指示用于构造此Uri的字符串是否格式良好,以及它是否不需要进一步转义。
[16]IsWellFormedUriString:通过尝试用字符串构造一个URI来指示字符串是否为格式良好的,并确保字符串不需要进一步转义。
[17]MakeRelativeUri:确定两个Uri实例之间的差异。
[18]TryCreate:已重载,创建一个新的Uri,在无法创建Uri时不引发异常。
[19]UnescapeDataString:将字符串转换为它的非转义表示形式。

参考文献:
[1]C#事件:https://www.runoob.com/csharp/csharp-event.html
[2]System.Linq Namespace:https://docs.microsoft.com/zh-cn/dotnet/api/system.linq?redirectedfrom=MSDN&view=netframework-4.8
[3]WPF入门教程系列一——基础:https://www.cnblogs.com/chillsrc/p/4464023.html
[4]WPF入门教程[23篇]:http://www.shouce.ren/api/view/a/15513
[5]microsoft/WPF-Samples:https://github.com/Microsoft/WPF-Samples
[6]Windows Presentation Foundation:https://docs.microsoft.com/zh-cn/dotnet/framework/wpf/
[7]WPF中的文档:https://docs.microsoft.com/zh-cn/dotnet/framework/wpf/advanced/documents-in-wpf
[8]类库 (WPF):https://docs.microsoft.com/zh-cn/dotnet/framework/wpf/class-library-wpf
[9]WPF Tutorial:https://www.wpf-tutorial.com/Localization/LanguageStatus/zh/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

NLP工程化

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值