c# 泛型方法语法

泛型方法是通过类型参数声明的方法,如下所示:
C#

 
static void Swap<T>(ref T lhs, ref T rhs)
{
    T temp;
    temp = lhs;
    lhs = rhs;
    rhs = temp;
}
如下示例演示使用类型参数的 int 调用方法的一种方式:
C#

 
public static void TestSwap()
{
    int a = 1;
    int b = 2;

    Swap<int>(ref a, ref b);
    System.Console.WriteLine(a + " " + b);
}
还可省略类型参数,编译器将推断类型参数。 如下 Swap 调用等效于之前的调用:
C#

 
Swap(ref a, ref b);
类型推理的相同规则适用于静态方法和实例方法。 编译器可基于传入的方法参数推断类型参数;而无法仅根据约束或返回值推断类型参数。 因此,类型推理不适用于不具有参数的方法。 类型推理发生在编译时,之后编译器尝试解析重载的方法签名。 编译器将类型推理逻辑应用于共用同一名称的所有泛型方法。 在重载解决方案步骤中,编译器仅包含在其上类型推理成功的泛型方法。
在泛型类中,非泛型方法可访问类级别类型参数,如下所示:
C#

 
class SampleClass<T>
{
    void Swap(ref T lhs, ref T rhs) { }
}

posted @ 2020-07-21 10:07 青蛙學堂 阅读(189) | 评论 (0)编辑 收藏

c# 泛型


泛型是.NET  work 2.0 版类库就已经提供的语法,主要用于提高代码的可重用性、类型安全性和效率。

泛型的定义
下面定义了一个普通类和一个泛型类,我们可以明确看到泛型类和普通类最大的区别就是多了一个<T>。

所以,这个<T>就标记了,这个类是泛型类。其中这个T,也可以写成A,B,C,D或其他字符。

 
public class Generic
{
  public String Name;
}
public class Generic<T>
{
  public T Name;
}
泛型,顾名思义,就是泛指的类型。好比男人,女人,白人,黑人,可以泛称为【人】。

但类型只能是一个类型。 那么泛型和类型之间是什么关系呢?

其实很简单,泛型在定义的时候,是泛指类型;在使用的时候,就需要被指定,到底使用哪个类型。

即,使用时,就不在是泛指类型,而是特定类型。

好比,定义时,定义了一个人。但在使用时,必须明确指定,到底是黑人还是白人。

泛型的使用
泛型类跟普通类的使用方式一样,都需要实例化对象,再由对象来调用内部的属性或方法。

下面代码实例化了泛型Generic,实例化时,还指定了该泛型Generic的指定类型为String。

所以要给泛型Generic的属性Name赋值,就需要赋值字符串类型的值。

 
public static void Excute()
{
  Generic<String> gs = new Generic<String>();
  gs.Name = "Kiba518";
}
下面代码定义了一个Int类型的泛型Generic。

 
public static void Excute()
{
  Generic<int> gs = new Generic<int>();
  gs.Name = 518;
}
泛型的默认值
泛型的默认值,如下面代码所示。需要使用default(T)来赋值。

不管泛型到底是String,int,bool或者是一个Class类型,都可以被自动赋值。

 
 
public static void Excute()
{
  Generic<int> gs = new Generic<int>();
  gs.Name = 518;
  Generic<Task> gsTask = new Generic<Task>();
  gsTask.Name = new Task(()=> {
    Console.WriteLine("Kiba518");
  });
}
  
public class Generic<T>
{
  public T Name = default(T);
}
泛型的约束
在泛型类中,有个特别的约束可供我们使用。

当我们不显示的声明时,这个约束不存在。但当我们显示的声明的时候,这个约束就会执行。

下面,我们来看看这个特别的约束。

 
public static void Excute()
{
  Generic<FanXing> gFanXing = new Generic<FanXing>();
  Generic< > gFanXing = new Generic< >();
  //Generic<string> gs = new Generic<string>(); 这样定义会报错
}
public class Generic<T> where T :
{
  public T Name = default(T);
}
public class 
{
  public string Name { getset; }
}
public class FanXing :
{
  public new string Name { getset; }
}
如上面代码所示,【where T :  】就是这个特别的约束。

当显示声明这个约束的时候,定义会限制泛型的类型。

什么是限制泛型的类型呢?

很简单,泛型T,是泛指某一个类型。我们在定义泛型类时,还需显示的指定类型,此时我们显示指定的类型,要受这个限制。

这个限制就是指【where T :  】。

它的限制是,要求我们指定的类型T必须是 ,或者该类型继承自 ,如FanXing类。

泛型的函数

在C#中,泛型不仅可以用于类,还可以直接用于函数。

具体使用方式如下:

 
public static void Excute()
{
  GenericFunc gf = new GenericFunc();
  gf.FanXingFunc<FanXing>(new FanXing() { Name="Kiba518"});
}
public class GenericFunc
{
  public void FanXingFunc<T>(T obj)
  {
    Console.WriteLine(obj.GetType());
  }
}

//泛型方法
  public T show<T>(T sParameter)
        {
            return sParameter;
        }

很简单,调用泛型函数的时候,指定泛型函数的[指定类型]即可。

但是,这里我们发现一个问题,那就是,在泛型函数里,使用泛型对象的时候,我们发现对象都是 类型的。

那我们如果想使用泛型对象里的属性和方法时,要怎么办呢?

也很简单,反射就可以了。

下面我们添加一个反射函数GetPropertyValue,专门用来获取属性。

 
public class GenericFunc
{
  public void FanXingFunc<T>(T obj)
  {
    var name = GetPropertyValue(obj, "Name");
    Console.WriteLine(name);
  }
  public  GetPropertyValue( obj, string name)
  {
     drv1 = obj.GetType().GetProperty(name).GetValue(obj, null);
    return drv1;
  }
}
输出结果如下:



这样我们就得到了我们想要的结果,如果想使用泛型类里的函数,道理也一样,只需要用反射来调用即可。

结语
看到这里,有些同学可能会觉得泛型很复杂,连使用其对象下的属性,都得反射,太繁琐了,还不如不用呢。

有这样想法的同学,心里想想就好了,如果对老司机这么说,他肯定会内心默默的微笑,然后对你说,你想的没错。

然后,你就没有然后了。

泛型的应用,开篇已经说了,主要用在提高代码的可重用性、类型安全性和效率上。

如果只是定义一个类,调用一个属性,那泛型的存在就是鸡肋。

但事实上,我们的系统永远只有更复杂,更复杂,更复杂。因此泛型才有了用武之地。

posted @ 2020-07-21 08:40 青蛙學堂 阅读(142) | 评论 (0)编辑 收藏

c# 字典

1. 使用字典原因

    通常情况下,我们可以通过int类型的索引号来从数组或者list集合中查询所需的数据。但是如果情况稍微复杂一点:索引号是非int型数据比如string或其他类型该如何操作呢。这个时候我们就可以使用字典了。

2. 什么是字典

    顾名思义,字典是一种让我们可以通过索引号查询到特定数据的数据结构类型。

    关键字 DIctionary

3. 用法及注意事项

   (1)  C#的Dictionary<Tkey,TValue>类在内部维护两个数组来实现该功能。一个keys数组容纳要从其映射的键,另一个values容纳映射到的值。在Dictionary<Tkey,TValue>集合中插入键/值对时,将自动记录哪

    个键和哪个值关联,从而允许开发人员快速和简单地获取具有指定键的值。

   (2)C#的Dictionary<Tkey,TValue>集合不能包含重复的键。调用Add方法添加键数组中已有的键将抛出异常。但是,如果使用方括号记法(类似给数组元素赋值)来添加键/值对,就不用担心异常——如果键已

    经存在,其值就会被新值覆盖。可用ContainKey方法测试Dictionary<Tkey,TValue>集合是否已包含特定的键。
   (3)Dictionary<Tkey,TValue>集合内部采用一种稀疏数据结构,在有大量内存可用时才最高效。随着更多元素的插入,Dictionary<Tkey,TValue>集合可能快速消耗大量内存。
   (4)用foreach遍历Dictionary<Tkey,TValue>集合返回一个KeyValuePair<Tkey,TValue>。该结构包含数据项的键和值拷贝,可通过Key和Value属性防蚊每个元素。元素是只读的,不能用它们修改Dictionary<Tkey,TValue>集合中的数据。

posted @ 2020-07-20 08:54 青蛙學堂 阅读(415) | 评论 (0)编辑 收藏

c# 特性 AttributeUsage



AttributeUsage】自定义特性时使用

  System.AttributeUsage声明一个Attribute的使用范围与使用原则。

  

  AllowMultiple 和 Inherited 参数是可选的,所以此代码具有相同的效果:

  

  AttributeTarget的值可以参考1。部分可取值如下:

  

  如果 AllowMultiple 参数设置为 true,则返回特性可对单个实体应用多次。

  如果 Inherited 设置为 false,则该特性不由从特性化的类派生的类继承。

  Attribute.GetCustomAttribute可以获取一个类的Attribute。

[AttributeUsage(AttributeTargets.Class)]
    public class VersionAttribute : Attribute
    {
        public string Name { getset; }
        public string Date { getset; }
        public string Describtion { getset; }
    }

 [Version(Name = "hyddd", Date = "2009-07-20", Describtion = "hyddd's class")]
    public class MyCode
    {
        //
    }

 class Program
    {
        static void Main(string[] args)
        {
            var info = typeof(MyCode);
            var classAttribute = (VersionAttribute)Attribute.GetCustomAttribute(info, typeof(VersionAttribute));
            Console.WriteLine(classAttribute.Name);
            Console.WriteLine(classAttribute.Date);
            Console.WriteLine(classAttribute.Describtion);
        }
    }

posted @ 2020-07-17 14:39 青蛙學堂 阅读(458) | 评论 (0)编辑 收藏

c# 线程中断



 
首先,一个线程不应该由其他线程来强制中断或停止,而是应该由线程自己自行停止。所以,Thread.stop, Thread.suspend, Thread.resume 都已经被废弃了。而 Thread.interrupt 的作用其实也不是中断线程,而是「通知线程应该中断了」,具体到底中断还是继续运行,应该由被通知的线程自己处理。具体来说,当对一个线程,调用 interrupt() 时,① 如果线程处于被阻塞状态(例如处于sleep, wait, join 等状态),那么线程将立即退出被阻塞状态,并抛出一个InterruptedException异常。仅此而已。② 如果线程处于正常活动状态,那么会将该线程的中断标志设置为 true,仅此而已。被设置中断标志的线程将继续正常运行,不受影响。interrupt() 并不能真正的中断线程,需要被调用的线程自己进行配合才行。也就是说,一个线程如果有被中断的需求,那么就可以这样做。① 在正常运行任务时,经常检查本线程的中断标志位,如果被设置了中断标志就自行停止线程。② 在调用阻塞方法时正确处理InterruptedException异常。(例如,catch异常后就结束线程。)Thread thread = new Thread(() -> {
    while (!Thread.interrupted()) {
        // do more work.
    }
});
thread.start();

// 一段时间以后
thread.interrupt();
具体到你的问题,Thread.interrupted()清除标志位是为了下次继续检测标志位。如果一个线程被设置中断标志后,选择结束线程那么自然不存在下次的问题,而如果一个线程被设置中断标识后,进行了一些处理后选择继续进行任务,而且这个任务也是需要被中断的,那么当然需要清除标志位了。

 

interrupted()是Java提供的一种中断机制,要把中断搞清楚,还是得先系统性了解下什么是中断机制。什么是中断?在Java中没有办法立即停止一条线程,然而停止线程却显得尤为重要,如取消一个耗时操作。因此,Java提供了一种用于停止线程的机制——中断。中断只是一种协作机制,Java没有给中断增加任何语法,中断的过程完全需要程序员自己实现。若要中断一个线程,你需要手动调用该线程的interrupted方法,该方法也仅仅是将线程对象的中断标识设成true;接着你需要自己写代码不断地检测当前线程的标识位;如果为true,表示别的线程要求这条线程中断,此时究竟该做什么需要你自己写代码实现。每个线程对象中都有一个标识,用于表示线程是否被中断;该标识位为true表示中断,为false表示未中断;通过调用线程对象的interrupt方法将该线程的标识位设为true;可以在别的线程中调用,也可以在自己的线程中调用。中断的相关方法public void interrupt() 将调用者线程的中断状态设为true。public boolean isInterrupted() 判断调用者线程的中断状态。public static boolean interrupted 只能通过Thread.interrupted()调用。 它会做两步操作:返回当前线程的中断状态;将当前线程的中断状态设为false;如何使用中断?要使用中断,首先需要在可能会发生中断的线程中不断监听中断状态,一旦发生中断,就执行相应的中断处理代码。 当需要中断线程时,调用该线程对象的interrupt函数即可。1.设置中断监听Thread t1 = new Thread( new Runnable(){
    public void run(){
        // 若未发生中断,就正常执行任务
        while(!Thread.currentThread.isInterrupted()){
            // 正常任务代码……
        }

        // 中断的处理代码……
        doSomething();
    }
} ).start();正常的任务代码被封装在while循环中,每次执行完一遍任务代码就检查一下中断状态;一旦发生中断,则跳过while循环,直接执行后面的中断处理代码。2.触发中断t1.interrupt();上述代码执行后会将t1对象的中断状态设为true,此时t1线程的正常任务代码执行完成后,进入下一次while循环前Thread.currentThread.isInterrupted()的结果为true,此时退出循环,执行循环后面的中断处理代码。如何安全地停止线程?stop函数停止线程过于暴力,它会立即停止线程,不给任何资源释放的余地,下面介绍两种安全停止线程的方法。1.循环标记变量自定义一个共享的boolean类型变量,表示当前线程是否需要中断。中断标识volatile boolean interrupted = false;任务执行函数Thread t1 = new Thread( new Runnable(){
    public void run(){
        while(!interrupted){
            // 正常任务代码……
        }
        // 中断处理代码……
        
// 可以在这里进行资源的释放等操作……
    }
} );中断函数Thread t2 = new Thread( new Runnable(){
    public void run(){
        interrupted = true;
    }
} );2.循环中断状态中断标识 由线程对象提供,无需自己定义。任务执行函数Thread t1 = new Thread( new Runnable(){
    public void run(){
        while(!Thread.currentThread.isInterrupted()){
            // 正常任务代码……
        }
        // 中断处理代码……
        
// 可以在这里进行资源的释放等操作……
    }
} );中断函数t1.interrupt();上述两种方法本质一样,都是通过循环查看一个共享标记为来判断线程是否需要中断,他们的区别在于:第一种方法的标识位是我们自己设定的,而第二种方法的标识位是Java提供的。除此之外,他们的实现方法是一样的。上述两种方法之所以较为安全,是因为一条线程发出终止信号后,接收线程并不会立即停止,而是将本次循环的任务执行完,再跳出循环停止线程。此外,程序员又可以在跳出循环后添加额外的代码进行收尾工作。如何处理中断?上文都在介绍如何获取中断状态,那么当我们捕获到中断状态后,究竟如何处理呢?Java类库中提供的一些可能会发生阻塞的方法都会抛InterruptedException异常,如:BlockingQueue#put、BlockingQueue#take、Object#wait、Thread#sleep。当你在某一条线程中调用这些方法时,这个方法可能会被阻塞很长时间,你可以在别的线程中调用当前线程对象的interrupt方法触发这些函数抛出InterruptedException异常。当一个函数抛出InterruptedException异常时,表示这个方法阻塞的时间太久了,别人不想等它执行结束了。当你的捕获到一个InterruptedException异常后,亦可以处理它,或者向上抛出。抛出时要注意???:当你捕获到InterruptedException异常后,当前线程的中断状态已经被修改为false(表示线程未被中断);此时你若能够处理中断,则不用理会该值;但如果你继续向上抛InterruptedException异常,你需要再次调用interrupt方法,将当前线程的中断状态设为true。注意:绝对不能“吞掉中断”!即捕获了InterruptedException而不作任何处理。这样违背了中断机制的规则,别人想让你线程中断,然而你自己不处理,也不将中断请求告诉调用者,调用者一直以为没有中断请求。

posted @ 2020-07-15 10:36 青蛙學堂 阅读(993) | 评论 (0)编辑 收藏

c# 线程中断机制(interrupt)


interrupt() 它基于「一个线程不应该由其他线程来强制中断或停止,而是应该由线程自己自行停止。」思想,是一个比较温柔的做法,它更类似一个标志位。其实作用不是中断线程,而是「通知线程应该中断了」,具体到底中断还是继续运行,应该由被通知的线程自己处理。

interrupt() 并不能真正的中断线程,这点要谨记。需要被调用的线程自己进行配合才行。也就是说,一个线程如果有被中断的需求,那么就需要这样做:

  1. 在正常运行任务时,经常检查本线程的中断标志位,如果被设置了中断标志就自行停止线程。
  2. 在调用阻塞方法时正确处理InterruptedException异常。(例如:catch异常后就结束线程。)

首先讲 interrupt() 方法:

  1. interrupt 中断操作时,非自身打断需要先检测是否有中断权限,这由jvm的安全机制配置;
  2. 如果线程处于sleep, wait, join 等状态,那么线程将立即退出被阻塞状态,并抛出一个InterruptedException异常;
  3. 如果线程处于I/O阻塞状态,将会抛出ClosedByInterruptException(IOException的子类)异常;
  4. 如果线程在Selector上被阻塞,select方法将立即返回;
  5. 如果非以上情况,将直接标记 interrupt 状态;

注意:interrupt 操作不会打断所有阻塞,只有上述阻塞情况才在jvm的打断范围内,如处于锁阻塞的线程,不会受 interrupt 中断;

阻塞情况下中断,抛出异常后线程恢复非中断状态,即 interrupted = false


 public class ThreadTest {
    
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(new Task("1"));
        t.start();
        t.interrupt();
    }

    static class Task implements Runnable{
        String name;
        
        public Task(String name) {
            this.name = name;
        }
        
        @Override
        public void run() {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                System.out.println("thread has been interrupt!");
            }
            System.out.println("isInterrupted: " + Thread.currentThread().isInterrupted());
            System.out.println("task " + name + " is over");
        }
    }
}
结果:
thread has been interrupt! isInterrupted: false task 1 is over
上述两种隐含的状态恢复操作,是符合常理的,因为线程标记为中断后,用户没有真正中断线程,必然将其恢复为false。理论上Thread.interrupted()调用后,如果已中断,应该执行退出操作,不会重复调用。

public class ThreadTest {
    
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(new Task("1"));
        t.start();
        t.interrupt();
    }

    static class Task implements Runnable{
        String name;
        
        public Task(String name) {
            this.name = name;
        }
        
        @Override
        public void run() {
            System.out.println("first :" + Thread.interrupted());
            System.out.println("second:" + Thread.interrupted());
            System.out.println("task " + name + " is over");
        }
    }
}

posted @ 2020-07-15 10:29 青蛙學堂 阅读(2610) | 评论 (0)编辑 收藏

c# 线程执行gridview 绑定

c# 线程执行gridview 绑定
需求:
一个web页面 default.aspx 里面有两个控件GridView1,GridView2,通过两个线程分别加载绑定数据。

绑定GridView1:
void BindCategory()
    {


        SqlConnection conn = ReturnSqlconn();
        SqlCommand comm = new SqlCommand("select * from category", conn);
        conn.Open();
        SqlDataReader sdr = comm.ExecuteReader();


        GridView1.DataSource = sdr;
        GridView1.DataBind();
    }

绑定GridView2:

void BindNews()
    {
        SqlConnection conn = ReturnSqlconn();
        SqlCommand comm = new SqlCommand("select * from News", conn);
        conn.Open();
        SqlDataReader sdr = comm.ExecuteReader();


        GridView2.DataSource = sdr;
        GridView2.DataBind();


    }

加载两个方法,绑定数据:

protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            try
            {
                Thread categoryThread = new Thread(new ThreadStart(BindCategory));
                Thread newsThread = new Thread(new ThreadStart(BindNews));


                categoryThread.Start();
                newsThread.Start();


                categoryThread.Join();
                newsThread.Join();
            }
            catch (Exception ex)
            {
                Response.Write(ex);
            }
        }
    }


实现效果


注意:
categoryThread.Join();
newsThread.Join();
这两个函数很关键,否则导致页面绑定失败;Join方法使创建的2个线程与页面加载同步;Join在MSND上的解释是:在继续执行标准的 COM 和 SendMessage 消息泵处理期间,阻塞调用线程,直到某个线程终止为止。

通过此方法可以实现单个页面的多线程处理以提高效率。

posted @ 2020-07-14 09:33 青蛙學堂 阅读(480) | 评论 (0)编辑 收藏

c# 委托

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

public delegate void GreetingDelegate(string name);
 
class Program
{
    private static void EnglishGreeting(string name)
    {
        Console.WriteLine("Good Morning, " + name);
    }
 
    private static void ChineseGreeting(string name)
    {
        Console.WriteLine("早上好, " + name);
    }
 
    private static void GreetPeople(string name, GreetingDelegate MakeGreeting)
    {
        MakeGreeting(name);
    }
 
    static void Main(string[] args)
    {
        GreetPeople("Liker", EnglishGreeting);
        GreetPeople("李志中", ChineseGreeting);
        Console.ReadLine();
    }
}

posted @ 2020-07-13 15:28 青蛙學堂 阅读(121) | 评论 (0)编辑 收藏

pace.js – 网页自动加载进度条插件

pace.js – 网页自动加载进度条插件

在页面中引入Pace.js,页面就会自动监测你的请求(包括Ajax请求),在事件循环滞后,会在页面记录加载的状态以及进度情况。此插件的兼容性很好,可以兼容IE8以上的所有主流插件,而且其强大之处在于,你还可以引入加载进度条的主题样式,你可以选择任意颜色和多种动画效果(例如简约、闪光灯,MAC OSX,左侧填充,顶部填充,计数器和弹跳等等动画效果),如果你擅长修改css动画,那你就可以做出无限种可能性的动画,为你的网站增添个性化特色!

使用方法

引入Pace.js以及主题文件即可:

1 <head>
2   <script src="/pace/pace.js"></script>
3   <link href="/pace/themes/pace-theme-barber-shop.css" rel="external nofollow"  rel="external nofollow"  rel="stylesheet" />
4 </head>

 


posted @ 2020-07-01 16:59 青蛙學堂 阅读(104) | 评论 (0)编辑 收藏

Jquery ajax示例get-post


Jquery ajax示例get-post
  $(function(){
       
 //请求参数
       
 var list = {};
       
 //
       
 $.ajax({
            
//请求方式
          
  type : "POST",
            
//请求的媒体类型
      
      
contentType: "application/json;charset=UTF-8",
          
  //请求地址
           
 url : "http://127.0.0.1/admin/list/",
           
 //数据,json字符串
           
 data : JSON.stringify(list),
            
//请求成功
            
success : function(result) {
              
  console.log(result);
          
  },
       
     //请求失败,包含具体的错误信息
  
          error : function(e){
              
  console.log(e.status);
               
 console.log(e.responseText);
         
   }
     
  
 });
 
  
 });
*******************************************************
$("button").click(function(){
  $.get("demo_test.asp",function(data,status){
    alert("Data: " + data + "\nStatus: " + status);
  });
});
***********************************************
$("button").click(function(){
  $.post("demo_test_post.asp",
  {
    name:"Donald Duck",
    city:"Duckburg"
  },
  function(data,status){
    alert("Data: " + data + "\nStatus: " + status);
  });
});

posted @ 2020-06-29 18:27 青蛙學堂 阅读(143) | 评论 (0)编辑 收藏

仅列出标题
共43页: First 2 3 4 5 6 7 8 9 10 Last 
<2024年4月>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

导航

统计

常用链接

留言簿(8)

随笔分类

随笔档案

收藏夹

青蛙学堂

最新评论

阅读排行榜

评论排行榜